Merge "Add qtip job to pod zte-virtual6"
[releng.git] / utils / test / testapi / 3rd_party / static / testapi-ui / assets / lib / angular / angular.js
1 /**
2  * @license AngularJS v1.3.15
3  * (c) 2010-2014 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window, document, undefined) {'use strict';
7
8 /**
9  * @description
10  *
11  * This object provides a utility for producing rich Error messages within
12  * Angular. It can be called as follows:
13  *
14  * var exampleMinErr = minErr('example');
15  * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16  *
17  * The above creates an instance of minErr in the example namespace. The
18  * resulting error will have a namespaced error code of example.one.  The
19  * resulting error will replace {0} with the value of foo, and {1} with the
20  * value of bar. The object is not restricted in the number of arguments it can
21  * take.
22  *
23  * If fewer arguments are specified than necessary for interpolation, the extra
24  * interpolation markers will be preserved in the final string.
25  *
26  * Since data will be parsed statically during a build step, some restrictions
27  * are applied with respect to how minErr instances are created and called.
28  * Instances should have names of the form namespaceMinErr for a minErr created
29  * using minErr('namespace') . Error codes, namespaces and template strings
30  * should all be static strings, not variables or general expressions.
31  *
32  * @param {string} module The namespace to use for the new minErr instance.
33  * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
34  *   error from returned function, for cases when a particular type of error is useful.
35  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
36  */
37
38 function minErr(module, ErrorConstructor) {
39   ErrorConstructor = ErrorConstructor || Error;
40   return function() {
41     var code = arguments[0],
42       prefix = '[' + (module ? module + ':' : '') + code + '] ',
43       template = arguments[1],
44       templateArgs = arguments,
45
46       message, i;
47
48     message = prefix + template.replace(/\{\d+\}/g, function(match) {
49       var index = +match.slice(1, -1), arg;
50
51       if (index + 2 < templateArgs.length) {
52         return toDebugString(templateArgs[index + 2]);
53       }
54       return match;
55     });
56
57     message = message + '\nhttp://errors.angularjs.org/1.3.15/' +
58       (module ? module + '/' : '') + code;
59     for (i = 2; i < arguments.length; i++) {
60       message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
61         encodeURIComponent(toDebugString(arguments[i]));
62     }
63     return new ErrorConstructor(message);
64   };
65 }
66
67 /* We need to tell jshint what variables are being exported */
68 /* global angular: true,
69   msie: true,
70   jqLite: true,
71   jQuery: true,
72   slice: true,
73   splice: true,
74   push: true,
75   toString: true,
76   ngMinErr: true,
77   angularModule: true,
78   uid: true,
79   REGEX_STRING_REGEXP: true,
80   VALIDITY_STATE_PROPERTY: true,
81
82   lowercase: true,
83   uppercase: true,
84   manualLowercase: true,
85   manualUppercase: true,
86   nodeName_: true,
87   isArrayLike: true,
88   forEach: true,
89   sortedKeys: true,
90   forEachSorted: true,
91   reverseParams: true,
92   nextUid: true,
93   setHashKey: true,
94   extend: true,
95   int: true,
96   inherit: true,
97   noop: true,
98   identity: true,
99   valueFn: true,
100   isUndefined: true,
101   isDefined: true,
102   isObject: true,
103   isString: true,
104   isNumber: true,
105   isDate: true,
106   isArray: true,
107   isFunction: true,
108   isRegExp: true,
109   isWindow: true,
110   isScope: true,
111   isFile: true,
112   isFormData: true,
113   isBlob: true,
114   isBoolean: true,
115   isPromiseLike: true,
116   trim: true,
117   escapeForRegexp: true,
118   isElement: true,
119   makeMap: true,
120   includes: true,
121   arrayRemove: true,
122   copy: true,
123   shallowCopy: true,
124   equals: true,
125   csp: true,
126   concat: true,
127   sliceArgs: true,
128   bind: true,
129   toJsonReplacer: true,
130   toJson: true,
131   fromJson: true,
132   startingTag: true,
133   tryDecodeURIComponent: true,
134   parseKeyValue: true,
135   toKeyValue: true,
136   encodeUriSegment: true,
137   encodeUriQuery: true,
138   angularInit: true,
139   bootstrap: true,
140   getTestability: true,
141   snake_case: true,
142   bindJQuery: true,
143   assertArg: true,
144   assertArgFn: true,
145   assertNotHasOwnProperty: true,
146   getter: true,
147   getBlockNodes: true,
148   hasOwnProperty: true,
149   createMap: true,
150
151   NODE_TYPE_ELEMENT: true,
152   NODE_TYPE_TEXT: true,
153   NODE_TYPE_COMMENT: true,
154   NODE_TYPE_DOCUMENT: true,
155   NODE_TYPE_DOCUMENT_FRAGMENT: true,
156 */
157
158 ////////////////////////////////////
159
160 /**
161  * @ngdoc module
162  * @name ng
163  * @module ng
164  * @description
165  *
166  * # ng (core module)
167  * The ng module is loaded by default when an AngularJS application is started. The module itself
168  * contains the essential components for an AngularJS application to function. The table below
169  * lists a high level breakdown of each of the services/factories, filters, directives and testing
170  * components available within this core module.
171  *
172  * <div doc-module-components="ng"></div>
173  */
174
175 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
176
177 // The name of a form control's ValidityState property.
178 // This is used so that it's possible for internal tests to create mock ValidityStates.
179 var VALIDITY_STATE_PROPERTY = 'validity';
180
181 /**
182  * @ngdoc function
183  * @name angular.lowercase
184  * @module ng
185  * @kind function
186  *
187  * @description Converts the specified string to lowercase.
188  * @param {string} string String to be converted to lowercase.
189  * @returns {string} Lowercased string.
190  */
191 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
192 var hasOwnProperty = Object.prototype.hasOwnProperty;
193
194 /**
195  * @ngdoc function
196  * @name angular.uppercase
197  * @module ng
198  * @kind function
199  *
200  * @description Converts the specified string to uppercase.
201  * @param {string} string String to be converted to uppercase.
202  * @returns {string} Uppercased string.
203  */
204 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
205
206
207 var manualLowercase = function(s) {
208   /* jshint bitwise: false */
209   return isString(s)
210       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
211       : s;
212 };
213 var manualUppercase = function(s) {
214   /* jshint bitwise: false */
215   return isString(s)
216       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
217       : s;
218 };
219
220
221 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
222 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
223 // with correct but slower alternatives.
224 if ('i' !== 'I'.toLowerCase()) {
225   lowercase = manualLowercase;
226   uppercase = manualUppercase;
227 }
228
229
230 var
231     msie,             // holds major version number for IE, or NaN if UA is not IE.
232     jqLite,           // delay binding since jQuery could be loaded after us.
233     jQuery,           // delay binding
234     slice             = [].slice,
235     splice            = [].splice,
236     push              = [].push,
237     toString          = Object.prototype.toString,
238     ngMinErr          = minErr('ng'),
239
240     /** @name angular */
241     angular           = window.angular || (window.angular = {}),
242     angularModule,
243     uid               = 0;
244
245 /**
246  * documentMode is an IE-only property
247  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
248  */
249 msie = document.documentMode;
250
251
252 /**
253  * @private
254  * @param {*} obj
255  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
256  *                   String ...)
257  */
258 function isArrayLike(obj) {
259   if (obj == null || isWindow(obj)) {
260     return false;
261   }
262
263   var length = obj.length;
264
265   if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
266     return true;
267   }
268
269   return isString(obj) || isArray(obj) || length === 0 ||
270          typeof length === 'number' && length > 0 && (length - 1) in obj;
271 }
272
273 /**
274  * @ngdoc function
275  * @name angular.forEach
276  * @module ng
277  * @kind function
278  *
279  * @description
280  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
281  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
282  * is the value of an object property or an array element, `key` is the object property key or
283  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
284  *
285  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
286  * using the `hasOwnProperty` method.
287  *
288  * Unlike ES262's
289  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
290  * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
291  * return the value provided.
292  *
293    ```js
294      var values = {name: 'misko', gender: 'male'};
295      var log = [];
296      angular.forEach(values, function(value, key) {
297        this.push(key + ': ' + value);
298      }, log);
299      expect(log).toEqual(['name: misko', 'gender: male']);
300    ```
301  *
302  * @param {Object|Array} obj Object to iterate over.
303  * @param {Function} iterator Iterator function.
304  * @param {Object=} context Object to become context (`this`) for the iterator function.
305  * @returns {Object|Array} Reference to `obj`.
306  */
307
308 function forEach(obj, iterator, context) {
309   var key, length;
310   if (obj) {
311     if (isFunction(obj)) {
312       for (key in obj) {
313         // Need to check if hasOwnProperty exists,
314         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
315         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
316           iterator.call(context, obj[key], key, obj);
317         }
318       }
319     } else if (isArray(obj) || isArrayLike(obj)) {
320       var isPrimitive = typeof obj !== 'object';
321       for (key = 0, length = obj.length; key < length; key++) {
322         if (isPrimitive || key in obj) {
323           iterator.call(context, obj[key], key, obj);
324         }
325       }
326     } else if (obj.forEach && obj.forEach !== forEach) {
327         obj.forEach(iterator, context, obj);
328     } else {
329       for (key in obj) {
330         if (obj.hasOwnProperty(key)) {
331           iterator.call(context, obj[key], key, obj);
332         }
333       }
334     }
335   }
336   return obj;
337 }
338
339 function sortedKeys(obj) {
340   return Object.keys(obj).sort();
341 }
342
343 function forEachSorted(obj, iterator, context) {
344   var keys = sortedKeys(obj);
345   for (var i = 0; i < keys.length; i++) {
346     iterator.call(context, obj[keys[i]], keys[i]);
347   }
348   return keys;
349 }
350
351
352 /**
353  * when using forEach the params are value, key, but it is often useful to have key, value.
354  * @param {function(string, *)} iteratorFn
355  * @returns {function(*, string)}
356  */
357 function reverseParams(iteratorFn) {
358   return function(value, key) { iteratorFn(key, value); };
359 }
360
361 /**
362  * A consistent way of creating unique IDs in angular.
363  *
364  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
365  * we hit number precision issues in JavaScript.
366  *
367  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
368  *
369  * @returns {number} an unique alpha-numeric string
370  */
371 function nextUid() {
372   return ++uid;
373 }
374
375
376 /**
377  * Set or clear the hashkey for an object.
378  * @param obj object
379  * @param h the hashkey (!truthy to delete the hashkey)
380  */
381 function setHashKey(obj, h) {
382   if (h) {
383     obj.$$hashKey = h;
384   } else {
385     delete obj.$$hashKey;
386   }
387 }
388
389 /**
390  * @ngdoc function
391  * @name angular.extend
392  * @module ng
393  * @kind function
394  *
395  * @description
396  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
397  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
398  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
399  * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
400  *
401  * @param {Object} dst Destination object.
402  * @param {...Object} src Source object(s).
403  * @returns {Object} Reference to `dst`.
404  */
405 function extend(dst) {
406   var h = dst.$$hashKey;
407
408   for (var i = 1, ii = arguments.length; i < ii; i++) {
409     var obj = arguments[i];
410     if (obj) {
411       var keys = Object.keys(obj);
412       for (var j = 0, jj = keys.length; j < jj; j++) {
413         var key = keys[j];
414         dst[key] = obj[key];
415       }
416     }
417   }
418
419   setHashKey(dst, h);
420   return dst;
421 }
422
423 function int(str) {
424   return parseInt(str, 10);
425 }
426
427
428 function inherit(parent, extra) {
429   return extend(Object.create(parent), extra);
430 }
431
432 /**
433  * @ngdoc function
434  * @name angular.noop
435  * @module ng
436  * @kind function
437  *
438  * @description
439  * A function that performs no operations. This function can be useful when writing code in the
440  * functional style.
441    ```js
442      function foo(callback) {
443        var result = calculateResult();
444        (callback || angular.noop)(result);
445      }
446    ```
447  */
448 function noop() {}
449 noop.$inject = [];
450
451
452 /**
453  * @ngdoc function
454  * @name angular.identity
455  * @module ng
456  * @kind function
457  *
458  * @description
459  * A function that returns its first argument. This function is useful when writing code in the
460  * functional style.
461  *
462    ```js
463      function transformer(transformationFn, value) {
464        return (transformationFn || angular.identity)(value);
465      };
466    ```
467   * @param {*} value to be returned.
468   * @returns {*} the value passed in.
469  */
470 function identity($) {return $;}
471 identity.$inject = [];
472
473
474 function valueFn(value) {return function() {return value;};}
475
476 /**
477  * @ngdoc function
478  * @name angular.isUndefined
479  * @module ng
480  * @kind function
481  *
482  * @description
483  * Determines if a reference is undefined.
484  *
485  * @param {*} value Reference to check.
486  * @returns {boolean} True if `value` is undefined.
487  */
488 function isUndefined(value) {return typeof value === 'undefined';}
489
490
491 /**
492  * @ngdoc function
493  * @name angular.isDefined
494  * @module ng
495  * @kind function
496  *
497  * @description
498  * Determines if a reference is defined.
499  *
500  * @param {*} value Reference to check.
501  * @returns {boolean} True if `value` is defined.
502  */
503 function isDefined(value) {return typeof value !== 'undefined';}
504
505
506 /**
507  * @ngdoc function
508  * @name angular.isObject
509  * @module ng
510  * @kind function
511  *
512  * @description
513  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
514  * considered to be objects. Note that JavaScript arrays are objects.
515  *
516  * @param {*} value Reference to check.
517  * @returns {boolean} True if `value` is an `Object` but not `null`.
518  */
519 function isObject(value) {
520   // http://jsperf.com/isobject4
521   return value !== null && typeof value === 'object';
522 }
523
524
525 /**
526  * @ngdoc function
527  * @name angular.isString
528  * @module ng
529  * @kind function
530  *
531  * @description
532  * Determines if a reference is a `String`.
533  *
534  * @param {*} value Reference to check.
535  * @returns {boolean} True if `value` is a `String`.
536  */
537 function isString(value) {return typeof value === 'string';}
538
539
540 /**
541  * @ngdoc function
542  * @name angular.isNumber
543  * @module ng
544  * @kind function
545  *
546  * @description
547  * Determines if a reference is a `Number`.
548  *
549  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
550  *
551  * If you wish to exclude these then you can use the native
552  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
553  * method.
554  *
555  * @param {*} value Reference to check.
556  * @returns {boolean} True if `value` is a `Number`.
557  */
558 function isNumber(value) {return typeof value === 'number';}
559
560
561 /**
562  * @ngdoc function
563  * @name angular.isDate
564  * @module ng
565  * @kind function
566  *
567  * @description
568  * Determines if a value is a date.
569  *
570  * @param {*} value Reference to check.
571  * @returns {boolean} True if `value` is a `Date`.
572  */
573 function isDate(value) {
574   return toString.call(value) === '[object Date]';
575 }
576
577
578 /**
579  * @ngdoc function
580  * @name angular.isArray
581  * @module ng
582  * @kind function
583  *
584  * @description
585  * Determines if a reference is an `Array`.
586  *
587  * @param {*} value Reference to check.
588  * @returns {boolean} True if `value` is an `Array`.
589  */
590 var isArray = Array.isArray;
591
592 /**
593  * @ngdoc function
594  * @name angular.isFunction
595  * @module ng
596  * @kind function
597  *
598  * @description
599  * Determines if a reference is a `Function`.
600  *
601  * @param {*} value Reference to check.
602  * @returns {boolean} True if `value` is a `Function`.
603  */
604 function isFunction(value) {return typeof value === 'function';}
605
606
607 /**
608  * Determines if a value is a regular expression object.
609  *
610  * @private
611  * @param {*} value Reference to check.
612  * @returns {boolean} True if `value` is a `RegExp`.
613  */
614 function isRegExp(value) {
615   return toString.call(value) === '[object RegExp]';
616 }
617
618
619 /**
620  * Checks if `obj` is a window object.
621  *
622  * @private
623  * @param {*} obj Object to check
624  * @returns {boolean} True if `obj` is a window obj.
625  */
626 function isWindow(obj) {
627   return obj && obj.window === obj;
628 }
629
630
631 function isScope(obj) {
632   return obj && obj.$evalAsync && obj.$watch;
633 }
634
635
636 function isFile(obj) {
637   return toString.call(obj) === '[object File]';
638 }
639
640
641 function isFormData(obj) {
642   return toString.call(obj) === '[object FormData]';
643 }
644
645
646 function isBlob(obj) {
647   return toString.call(obj) === '[object Blob]';
648 }
649
650
651 function isBoolean(value) {
652   return typeof value === 'boolean';
653 }
654
655
656 function isPromiseLike(obj) {
657   return obj && isFunction(obj.then);
658 }
659
660
661 var trim = function(value) {
662   return isString(value) ? value.trim() : value;
663 };
664
665 // Copied from:
666 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
667 // Prereq: s is a string.
668 var escapeForRegexp = function(s) {
669   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
670            replace(/\x08/g, '\\x08');
671 };
672
673
674 /**
675  * @ngdoc function
676  * @name angular.isElement
677  * @module ng
678  * @kind function
679  *
680  * @description
681  * Determines if a reference is a DOM element (or wrapped jQuery element).
682  *
683  * @param {*} value Reference to check.
684  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
685  */
686 function isElement(node) {
687   return !!(node &&
688     (node.nodeName  // we are a direct element
689     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
690 }
691
692 /**
693  * @param str 'key1,key2,...'
694  * @returns {object} in the form of {key1:true, key2:true, ...}
695  */
696 function makeMap(str) {
697   var obj = {}, items = str.split(","), i;
698   for (i = 0; i < items.length; i++)
699     obj[items[i]] = true;
700   return obj;
701 }
702
703
704 function nodeName_(element) {
705   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
706 }
707
708 function includes(array, obj) {
709   return Array.prototype.indexOf.call(array, obj) != -1;
710 }
711
712 function arrayRemove(array, value) {
713   var index = array.indexOf(value);
714   if (index >= 0)
715     array.splice(index, 1);
716   return value;
717 }
718
719 /**
720  * @ngdoc function
721  * @name angular.copy
722  * @module ng
723  * @kind function
724  *
725  * @description
726  * Creates a deep copy of `source`, which should be an object or an array.
727  *
728  * * If no destination is supplied, a copy of the object or array is created.
729  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
730  *   are deleted and then all elements/properties from the source are copied to it.
731  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
732  * * If `source` is identical to 'destination' an exception will be thrown.
733  *
734  * @param {*} source The source that will be used to make a copy.
735  *                   Can be any type, including primitives, `null`, and `undefined`.
736  * @param {(Object|Array)=} destination Destination into which the source is copied. If
737  *     provided, must be of the same type as `source`.
738  * @returns {*} The copy or updated `destination`, if `destination` was specified.
739  *
740  * @example
741  <example module="copyExample">
742  <file name="index.html">
743  <div ng-controller="ExampleController">
744  <form novalidate class="simple-form">
745  Name: <input type="text" ng-model="user.name" /><br />
746  E-mail: <input type="email" ng-model="user.email" /><br />
747  Gender: <input type="radio" ng-model="user.gender" value="male" />male
748  <input type="radio" ng-model="user.gender" value="female" />female<br />
749  <button ng-click="reset()">RESET</button>
750  <button ng-click="update(user)">SAVE</button>
751  </form>
752  <pre>form = {{user | json}}</pre>
753  <pre>master = {{master | json}}</pre>
754  </div>
755
756  <script>
757   angular.module('copyExample', [])
758     .controller('ExampleController', ['$scope', function($scope) {
759       $scope.master= {};
760
761       $scope.update = function(user) {
762         // Example with 1 argument
763         $scope.master= angular.copy(user);
764       };
765
766       $scope.reset = function() {
767         // Example with 2 arguments
768         angular.copy($scope.master, $scope.user);
769       };
770
771       $scope.reset();
772     }]);
773  </script>
774  </file>
775  </example>
776  */
777 function copy(source, destination, stackSource, stackDest) {
778   if (isWindow(source) || isScope(source)) {
779     throw ngMinErr('cpws',
780       "Can't copy! Making copies of Window or Scope instances is not supported.");
781   }
782
783   if (!destination) {
784     destination = source;
785     if (source) {
786       if (isArray(source)) {
787         destination = copy(source, [], stackSource, stackDest);
788       } else if (isDate(source)) {
789         destination = new Date(source.getTime());
790       } else if (isRegExp(source)) {
791         destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
792         destination.lastIndex = source.lastIndex;
793       } else if (isObject(source)) {
794         var emptyObject = Object.create(Object.getPrototypeOf(source));
795         destination = copy(source, emptyObject, stackSource, stackDest);
796       }
797     }
798   } else {
799     if (source === destination) throw ngMinErr('cpi',
800       "Can't copy! Source and destination are identical.");
801
802     stackSource = stackSource || [];
803     stackDest = stackDest || [];
804
805     if (isObject(source)) {
806       var index = stackSource.indexOf(source);
807       if (index !== -1) return stackDest[index];
808
809       stackSource.push(source);
810       stackDest.push(destination);
811     }
812
813     var result;
814     if (isArray(source)) {
815       destination.length = 0;
816       for (var i = 0; i < source.length; i++) {
817         result = copy(source[i], null, stackSource, stackDest);
818         if (isObject(source[i])) {
819           stackSource.push(source[i]);
820           stackDest.push(result);
821         }
822         destination.push(result);
823       }
824     } else {
825       var h = destination.$$hashKey;
826       if (isArray(destination)) {
827         destination.length = 0;
828       } else {
829         forEach(destination, function(value, key) {
830           delete destination[key];
831         });
832       }
833       for (var key in source) {
834         if (source.hasOwnProperty(key)) {
835           result = copy(source[key], null, stackSource, stackDest);
836           if (isObject(source[key])) {
837             stackSource.push(source[key]);
838             stackDest.push(result);
839           }
840           destination[key] = result;
841         }
842       }
843       setHashKey(destination,h);
844     }
845
846   }
847   return destination;
848 }
849
850 /**
851  * Creates a shallow copy of an object, an array or a primitive.
852  *
853  * Assumes that there are no proto properties for objects.
854  */
855 function shallowCopy(src, dst) {
856   if (isArray(src)) {
857     dst = dst || [];
858
859     for (var i = 0, ii = src.length; i < ii; i++) {
860       dst[i] = src[i];
861     }
862   } else if (isObject(src)) {
863     dst = dst || {};
864
865     for (var key in src) {
866       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
867         dst[key] = src[key];
868       }
869     }
870   }
871
872   return dst || src;
873 }
874
875
876 /**
877  * @ngdoc function
878  * @name angular.equals
879  * @module ng
880  * @kind function
881  *
882  * @description
883  * Determines if two objects or two values are equivalent. Supports value types, regular
884  * expressions, arrays and objects.
885  *
886  * Two objects or values are considered equivalent if at least one of the following is true:
887  *
888  * * Both objects or values pass `===` comparison.
889  * * Both objects or values are of the same type and all of their properties are equal by
890  *   comparing them with `angular.equals`.
891  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
892  * * Both values represent the same regular expression (In JavaScript,
893  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
894  *   representation matches).
895  *
896  * During a property comparison, properties of `function` type and properties with names
897  * that begin with `$` are ignored.
898  *
899  * Scope and DOMWindow objects are being compared only by identify (`===`).
900  *
901  * @param {*} o1 Object or value to compare.
902  * @param {*} o2 Object or value to compare.
903  * @returns {boolean} True if arguments are equal.
904  */
905 function equals(o1, o2) {
906   if (o1 === o2) return true;
907   if (o1 === null || o2 === null) return false;
908   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
909   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
910   if (t1 == t2) {
911     if (t1 == 'object') {
912       if (isArray(o1)) {
913         if (!isArray(o2)) return false;
914         if ((length = o1.length) == o2.length) {
915           for (key = 0; key < length; key++) {
916             if (!equals(o1[key], o2[key])) return false;
917           }
918           return true;
919         }
920       } else if (isDate(o1)) {
921         if (!isDate(o2)) return false;
922         return equals(o1.getTime(), o2.getTime());
923       } else if (isRegExp(o1)) {
924         return isRegExp(o2) ? o1.toString() == o2.toString() : false;
925       } else {
926         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
927           isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
928         keySet = {};
929         for (key in o1) {
930           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
931           if (!equals(o1[key], o2[key])) return false;
932           keySet[key] = true;
933         }
934         for (key in o2) {
935           if (!keySet.hasOwnProperty(key) &&
936               key.charAt(0) !== '$' &&
937               o2[key] !== undefined &&
938               !isFunction(o2[key])) return false;
939         }
940         return true;
941       }
942     }
943   }
944   return false;
945 }
946
947 var csp = function() {
948   if (isDefined(csp.isActive_)) return csp.isActive_;
949
950   var active = !!(document.querySelector('[ng-csp]') ||
951                   document.querySelector('[data-ng-csp]'));
952
953   if (!active) {
954     try {
955       /* jshint -W031, -W054 */
956       new Function('');
957       /* jshint +W031, +W054 */
958     } catch (e) {
959       active = true;
960     }
961   }
962
963   return (csp.isActive_ = active);
964 };
965
966
967
968 function concat(array1, array2, index) {
969   return array1.concat(slice.call(array2, index));
970 }
971
972 function sliceArgs(args, startIndex) {
973   return slice.call(args, startIndex || 0);
974 }
975
976
977 /* jshint -W101 */
978 /**
979  * @ngdoc function
980  * @name angular.bind
981  * @module ng
982  * @kind function
983  *
984  * @description
985  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
986  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
987  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
988  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
989  *
990  * @param {Object} self Context which `fn` should be evaluated in.
991  * @param {function()} fn Function to be bound.
992  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
993  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
994  */
995 /* jshint +W101 */
996 function bind(self, fn) {
997   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
998   if (isFunction(fn) && !(fn instanceof RegExp)) {
999     return curryArgs.length
1000       ? function() {
1001           return arguments.length
1002             ? fn.apply(self, concat(curryArgs, arguments, 0))
1003             : fn.apply(self, curryArgs);
1004         }
1005       : function() {
1006           return arguments.length
1007             ? fn.apply(self, arguments)
1008             : fn.call(self);
1009         };
1010   } else {
1011     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1012     return fn;
1013   }
1014 }
1015
1016
1017 function toJsonReplacer(key, value) {
1018   var val = value;
1019
1020   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1021     val = undefined;
1022   } else if (isWindow(value)) {
1023     val = '$WINDOW';
1024   } else if (value &&  document === value) {
1025     val = '$DOCUMENT';
1026   } else if (isScope(value)) {
1027     val = '$SCOPE';
1028   }
1029
1030   return val;
1031 }
1032
1033
1034 /**
1035  * @ngdoc function
1036  * @name angular.toJson
1037  * @module ng
1038  * @kind function
1039  *
1040  * @description
1041  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1042  * stripped since angular uses this notation internally.
1043  *
1044  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1045  * @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace.
1046  *    If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2).
1047  * @returns {string|undefined} JSON-ified string representing `obj`.
1048  */
1049 function toJson(obj, pretty) {
1050   if (typeof obj === 'undefined') return undefined;
1051   if (!isNumber(pretty)) {
1052     pretty = pretty ? 2 : null;
1053   }
1054   return JSON.stringify(obj, toJsonReplacer, pretty);
1055 }
1056
1057
1058 /**
1059  * @ngdoc function
1060  * @name angular.fromJson
1061  * @module ng
1062  * @kind function
1063  *
1064  * @description
1065  * Deserializes a JSON string.
1066  *
1067  * @param {string} json JSON string to deserialize.
1068  * @returns {Object|Array|string|number} Deserialized JSON string.
1069  */
1070 function fromJson(json) {
1071   return isString(json)
1072       ? JSON.parse(json)
1073       : json;
1074 }
1075
1076
1077 /**
1078  * @returns {string} Returns the string representation of the element.
1079  */
1080 function startingTag(element) {
1081   element = jqLite(element).clone();
1082   try {
1083     // turns out IE does not let you set .html() on elements which
1084     // are not allowed to have children. So we just ignore it.
1085     element.empty();
1086   } catch (e) {}
1087   var elemHtml = jqLite('<div>').append(element).html();
1088   try {
1089     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1090         elemHtml.
1091           match(/^(<[^>]+>)/)[1].
1092           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1093   } catch (e) {
1094     return lowercase(elemHtml);
1095   }
1096
1097 }
1098
1099
1100 /////////////////////////////////////////////////
1101
1102 /**
1103  * Tries to decode the URI component without throwing an exception.
1104  *
1105  * @private
1106  * @param str value potential URI component to check.
1107  * @returns {boolean} True if `value` can be decoded
1108  * with the decodeURIComponent function.
1109  */
1110 function tryDecodeURIComponent(value) {
1111   try {
1112     return decodeURIComponent(value);
1113   } catch (e) {
1114     // Ignore any invalid uri component
1115   }
1116 }
1117
1118
1119 /**
1120  * Parses an escaped url query string into key-value pairs.
1121  * @returns {Object.<string,boolean|Array>}
1122  */
1123 function parseKeyValue(/**string*/keyValue) {
1124   var obj = {}, key_value, key;
1125   forEach((keyValue || "").split('&'), function(keyValue) {
1126     if (keyValue) {
1127       key_value = keyValue.replace(/\+/g,'%20').split('=');
1128       key = tryDecodeURIComponent(key_value[0]);
1129       if (isDefined(key)) {
1130         var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1131         if (!hasOwnProperty.call(obj, key)) {
1132           obj[key] = val;
1133         } else if (isArray(obj[key])) {
1134           obj[key].push(val);
1135         } else {
1136           obj[key] = [obj[key],val];
1137         }
1138       }
1139     }
1140   });
1141   return obj;
1142 }
1143
1144 function toKeyValue(obj) {
1145   var parts = [];
1146   forEach(obj, function(value, key) {
1147     if (isArray(value)) {
1148       forEach(value, function(arrayValue) {
1149         parts.push(encodeUriQuery(key, true) +
1150                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1151       });
1152     } else {
1153     parts.push(encodeUriQuery(key, true) +
1154                (value === true ? '' : '=' + encodeUriQuery(value, true)));
1155     }
1156   });
1157   return parts.length ? parts.join('&') : '';
1158 }
1159
1160
1161 /**
1162  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1163  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1164  * segments:
1165  *    segment       = *pchar
1166  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1167  *    pct-encoded   = "%" HEXDIG HEXDIG
1168  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1169  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1170  *                     / "*" / "+" / "," / ";" / "="
1171  */
1172 function encodeUriSegment(val) {
1173   return encodeUriQuery(val, true).
1174              replace(/%26/gi, '&').
1175              replace(/%3D/gi, '=').
1176              replace(/%2B/gi, '+');
1177 }
1178
1179
1180 /**
1181  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1182  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1183  * encoded per http://tools.ietf.org/html/rfc3986:
1184  *    query       = *( pchar / "/" / "?" )
1185  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1186  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1187  *    pct-encoded   = "%" HEXDIG HEXDIG
1188  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1189  *                     / "*" / "+" / "," / ";" / "="
1190  */
1191 function encodeUriQuery(val, pctEncodeSpaces) {
1192   return encodeURIComponent(val).
1193              replace(/%40/gi, '@').
1194              replace(/%3A/gi, ':').
1195              replace(/%24/g, '$').
1196              replace(/%2C/gi, ',').
1197              replace(/%3B/gi, ';').
1198              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1199 }
1200
1201 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1202
1203 function getNgAttribute(element, ngAttr) {
1204   var attr, i, ii = ngAttrPrefixes.length;
1205   element = jqLite(element);
1206   for (i = 0; i < ii; ++i) {
1207     attr = ngAttrPrefixes[i] + ngAttr;
1208     if (isString(attr = element.attr(attr))) {
1209       return attr;
1210     }
1211   }
1212   return null;
1213 }
1214
1215 /**
1216  * @ngdoc directive
1217  * @name ngApp
1218  * @module ng
1219  *
1220  * @element ANY
1221  * @param {angular.Module} ngApp an optional application
1222  *   {@link angular.module module} name to load.
1223  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1224  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1225  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1226  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1227  *   tracking down the root of these bugs.
1228  *
1229  * @description
1230  *
1231  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1232  * designates the **root element** of the application and is typically placed near the root element
1233  * of the page - e.g. on the `<body>` or `<html>` tags.
1234  *
1235  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1236  * found in the document will be used to define the root element to auto-bootstrap as an
1237  * application. To run multiple applications in an HTML document you must manually bootstrap them using
1238  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1239  *
1240  * You can specify an **AngularJS module** to be used as the root module for the application.  This
1241  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1242  * should contain the application code needed or have dependencies on other modules that will
1243  * contain the code. See {@link angular.module} for more information.
1244  *
1245  * In the example below if the `ngApp` directive were not placed on the `html` element then the
1246  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1247  * would not be resolved to `3`.
1248  *
1249  * `ngApp` is the easiest, and most common way to bootstrap an application.
1250  *
1251  <example module="ngAppDemo">
1252    <file name="index.html">
1253    <div ng-controller="ngAppDemoController">
1254      I can add: {{a}} + {{b}} =  {{ a+b }}
1255    </div>
1256    </file>
1257    <file name="script.js">
1258    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1259      $scope.a = 1;
1260      $scope.b = 2;
1261    });
1262    </file>
1263  </example>
1264  *
1265  * Using `ngStrictDi`, you would see something like this:
1266  *
1267  <example ng-app-included="true">
1268    <file name="index.html">
1269    <div ng-app="ngAppStrictDemo" ng-strict-di>
1270        <div ng-controller="GoodController1">
1271            I can add: {{a}} + {{b}} =  {{ a+b }}
1272
1273            <p>This renders because the controller does not fail to
1274               instantiate, by using explicit annotation style (see
1275               script.js for details)
1276            </p>
1277        </div>
1278
1279        <div ng-controller="GoodController2">
1280            Name: <input ng-model="name"><br />
1281            Hello, {{name}}!
1282
1283            <p>This renders because the controller does not fail to
1284               instantiate, by using explicit annotation style
1285               (see script.js for details)
1286            </p>
1287        </div>
1288
1289        <div ng-controller="BadController">
1290            I can add: {{a}} + {{b}} =  {{ a+b }}
1291
1292            <p>The controller could not be instantiated, due to relying
1293               on automatic function annotations (which are disabled in
1294               strict mode). As such, the content of this section is not
1295               interpolated, and there should be an error in your web console.
1296            </p>
1297        </div>
1298    </div>
1299    </file>
1300    <file name="script.js">
1301    angular.module('ngAppStrictDemo', [])
1302      // BadController will fail to instantiate, due to relying on automatic function annotation,
1303      // rather than an explicit annotation
1304      .controller('BadController', function($scope) {
1305        $scope.a = 1;
1306        $scope.b = 2;
1307      })
1308      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1309      // due to using explicit annotations using the array style and $inject property, respectively.
1310      .controller('GoodController1', ['$scope', function($scope) {
1311        $scope.a = 1;
1312        $scope.b = 2;
1313      }])
1314      .controller('GoodController2', GoodController2);
1315      function GoodController2($scope) {
1316        $scope.name = "World";
1317      }
1318      GoodController2.$inject = ['$scope'];
1319    </file>
1320    <file name="style.css">
1321    div[ng-controller] {
1322        margin-bottom: 1em;
1323        -webkit-border-radius: 4px;
1324        border-radius: 4px;
1325        border: 1px solid;
1326        padding: .5em;
1327    }
1328    div[ng-controller^=Good] {
1329        border-color: #d6e9c6;
1330        background-color: #dff0d8;
1331        color: #3c763d;
1332    }
1333    div[ng-controller^=Bad] {
1334        border-color: #ebccd1;
1335        background-color: #f2dede;
1336        color: #a94442;
1337        margin-bottom: 0;
1338    }
1339    </file>
1340  </example>
1341  */
1342 function angularInit(element, bootstrap) {
1343   var appElement,
1344       module,
1345       config = {};
1346
1347   // The element `element` has priority over any other element
1348   forEach(ngAttrPrefixes, function(prefix) {
1349     var name = prefix + 'app';
1350
1351     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1352       appElement = element;
1353       module = element.getAttribute(name);
1354     }
1355   });
1356   forEach(ngAttrPrefixes, function(prefix) {
1357     var name = prefix + 'app';
1358     var candidate;
1359
1360     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1361       appElement = candidate;
1362       module = candidate.getAttribute(name);
1363     }
1364   });
1365   if (appElement) {
1366     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1367     bootstrap(appElement, module ? [module] : [], config);
1368   }
1369 }
1370
1371 /**
1372  * @ngdoc function
1373  * @name angular.bootstrap
1374  * @module ng
1375  * @description
1376  * Use this function to manually start up angular application.
1377  *
1378  * See: {@link guide/bootstrap Bootstrap}
1379  *
1380  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1381  * They must use {@link ng.directive:ngApp ngApp}.
1382  *
1383  * Angular will detect if it has been loaded into the browser more than once and only allow the
1384  * first loaded script to be bootstrapped and will report a warning to the browser console for
1385  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1386  * multiple instances of Angular try to work on the DOM.
1387  *
1388  * ```html
1389  * <!doctype html>
1390  * <html>
1391  * <body>
1392  * <div ng-controller="WelcomeController">
1393  *   {{greeting}}
1394  * </div>
1395  *
1396  * <script src="angular.js"></script>
1397  * <script>
1398  *   var app = angular.module('demo', [])
1399  *   .controller('WelcomeController', function($scope) {
1400  *       $scope.greeting = 'Welcome!';
1401  *   });
1402  *   angular.bootstrap(document, ['demo']);
1403  * </script>
1404  * </body>
1405  * </html>
1406  * ```
1407  *
1408  * @param {DOMElement} element DOM element which is the root of angular application.
1409  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1410  *     Each item in the array should be the name of a predefined module or a (DI annotated)
1411  *     function that will be invoked by the injector as a `config` block.
1412  *     See: {@link angular.module modules}
1413  * @param {Object=} config an object for defining configuration options for the application. The
1414  *     following keys are supported:
1415  *
1416  * * `strictDi` - disable automatic function annotation for the application. This is meant to
1417  *   assist in finding bugs which break minified code. Defaults to `false`.
1418  *
1419  * @returns {auto.$injector} Returns the newly created injector for this app.
1420  */
1421 function bootstrap(element, modules, config) {
1422   if (!isObject(config)) config = {};
1423   var defaultConfig = {
1424     strictDi: false
1425   };
1426   config = extend(defaultConfig, config);
1427   var doBootstrap = function() {
1428     element = jqLite(element);
1429
1430     if (element.injector()) {
1431       var tag = (element[0] === document) ? 'document' : startingTag(element);
1432       //Encode angle brackets to prevent input from being sanitized to empty string #8683
1433       throw ngMinErr(
1434           'btstrpd',
1435           "App Already Bootstrapped with this Element '{0}'",
1436           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1437     }
1438
1439     modules = modules || [];
1440     modules.unshift(['$provide', function($provide) {
1441       $provide.value('$rootElement', element);
1442     }]);
1443
1444     if (config.debugInfoEnabled) {
1445       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1446       modules.push(['$compileProvider', function($compileProvider) {
1447         $compileProvider.debugInfoEnabled(true);
1448       }]);
1449     }
1450
1451     modules.unshift('ng');
1452     var injector = createInjector(modules, config.strictDi);
1453     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1454        function bootstrapApply(scope, element, compile, injector) {
1455         scope.$apply(function() {
1456           element.data('$injector', injector);
1457           compile(element)(scope);
1458         });
1459       }]
1460     );
1461     return injector;
1462   };
1463
1464   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1465   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1466
1467   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1468     config.debugInfoEnabled = true;
1469     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1470   }
1471
1472   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1473     return doBootstrap();
1474   }
1475
1476   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1477   angular.resumeBootstrap = function(extraModules) {
1478     forEach(extraModules, function(module) {
1479       modules.push(module);
1480     });
1481     return doBootstrap();
1482   };
1483
1484   if (isFunction(angular.resumeDeferredBootstrap)) {
1485     angular.resumeDeferredBootstrap();
1486   }
1487 }
1488
1489 /**
1490  * @ngdoc function
1491  * @name angular.reloadWithDebugInfo
1492  * @module ng
1493  * @description
1494  * Use this function to reload the current application with debug information turned on.
1495  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1496  *
1497  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1498  */
1499 function reloadWithDebugInfo() {
1500   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1501   window.location.reload();
1502 }
1503
1504 /**
1505  * @name angular.getTestability
1506  * @module ng
1507  * @description
1508  * Get the testability service for the instance of Angular on the given
1509  * element.
1510  * @param {DOMElement} element DOM element which is the root of angular application.
1511  */
1512 function getTestability(rootElement) {
1513   var injector = angular.element(rootElement).injector();
1514   if (!injector) {
1515     throw ngMinErr('test',
1516       'no injector found for element argument to getTestability');
1517   }
1518   return injector.get('$$testability');
1519 }
1520
1521 var SNAKE_CASE_REGEXP = /[A-Z]/g;
1522 function snake_case(name, separator) {
1523   separator = separator || '_';
1524   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1525     return (pos ? separator : '') + letter.toLowerCase();
1526   });
1527 }
1528
1529 var bindJQueryFired = false;
1530 var skipDestroyOnNextJQueryCleanData;
1531 function bindJQuery() {
1532   var originalCleanData;
1533
1534   if (bindJQueryFired) {
1535     return;
1536   }
1537
1538   // bind to jQuery if present;
1539   jQuery = window.jQuery;
1540   // Use jQuery if it exists with proper functionality, otherwise default to us.
1541   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1542   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1543   // versions. It will not work for sure with jQuery <1.7, though.
1544   if (jQuery && jQuery.fn.on) {
1545     jqLite = jQuery;
1546     extend(jQuery.fn, {
1547       scope: JQLitePrototype.scope,
1548       isolateScope: JQLitePrototype.isolateScope,
1549       controller: JQLitePrototype.controller,
1550       injector: JQLitePrototype.injector,
1551       inheritedData: JQLitePrototype.inheritedData
1552     });
1553
1554     // All nodes removed from the DOM via various jQuery APIs like .remove()
1555     // are passed through jQuery.cleanData. Monkey-patch this method to fire
1556     // the $destroy event on all removed nodes.
1557     originalCleanData = jQuery.cleanData;
1558     jQuery.cleanData = function(elems) {
1559       var events;
1560       if (!skipDestroyOnNextJQueryCleanData) {
1561         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1562           events = jQuery._data(elem, "events");
1563           if (events && events.$destroy) {
1564             jQuery(elem).triggerHandler('$destroy');
1565           }
1566         }
1567       } else {
1568         skipDestroyOnNextJQueryCleanData = false;
1569       }
1570       originalCleanData(elems);
1571     };
1572   } else {
1573     jqLite = JQLite;
1574   }
1575
1576   angular.element = jqLite;
1577
1578   // Prevent double-proxying.
1579   bindJQueryFired = true;
1580 }
1581
1582 /**
1583  * throw error if the argument is falsy.
1584  */
1585 function assertArg(arg, name, reason) {
1586   if (!arg) {
1587     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1588   }
1589   return arg;
1590 }
1591
1592 function assertArgFn(arg, name, acceptArrayAnnotation) {
1593   if (acceptArrayAnnotation && isArray(arg)) {
1594       arg = arg[arg.length - 1];
1595   }
1596
1597   assertArg(isFunction(arg), name, 'not a function, got ' +
1598       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1599   return arg;
1600 }
1601
1602 /**
1603  * throw error if the name given is hasOwnProperty
1604  * @param  {String} name    the name to test
1605  * @param  {String} context the context in which the name is used, such as module or directive
1606  */
1607 function assertNotHasOwnProperty(name, context) {
1608   if (name === 'hasOwnProperty') {
1609     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1610   }
1611 }
1612
1613 /**
1614  * Return the value accessible from the object by path. Any undefined traversals are ignored
1615  * @param {Object} obj starting object
1616  * @param {String} path path to traverse
1617  * @param {boolean} [bindFnToScope=true]
1618  * @returns {Object} value as accessible by path
1619  */
1620 //TODO(misko): this function needs to be removed
1621 function getter(obj, path, bindFnToScope) {
1622   if (!path) return obj;
1623   var keys = path.split('.');
1624   var key;
1625   var lastInstance = obj;
1626   var len = keys.length;
1627
1628   for (var i = 0; i < len; i++) {
1629     key = keys[i];
1630     if (obj) {
1631       obj = (lastInstance = obj)[key];
1632     }
1633   }
1634   if (!bindFnToScope && isFunction(obj)) {
1635     return bind(lastInstance, obj);
1636   }
1637   return obj;
1638 }
1639
1640 /**
1641  * Return the DOM siblings between the first and last node in the given array.
1642  * @param {Array} array like object
1643  * @returns {jqLite} jqLite collection containing the nodes
1644  */
1645 function getBlockNodes(nodes) {
1646   // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
1647   //             collection, otherwise update the original collection.
1648   var node = nodes[0];
1649   var endNode = nodes[nodes.length - 1];
1650   var blockNodes = [node];
1651
1652   do {
1653     node = node.nextSibling;
1654     if (!node) break;
1655     blockNodes.push(node);
1656   } while (node !== endNode);
1657
1658   return jqLite(blockNodes);
1659 }
1660
1661
1662 /**
1663  * Creates a new object without a prototype. This object is useful for lookup without having to
1664  * guard against prototypically inherited properties via hasOwnProperty.
1665  *
1666  * Related micro-benchmarks:
1667  * - http://jsperf.com/object-create2
1668  * - http://jsperf.com/proto-map-lookup/2
1669  * - http://jsperf.com/for-in-vs-object-keys2
1670  *
1671  * @returns {Object}
1672  */
1673 function createMap() {
1674   return Object.create(null);
1675 }
1676
1677 var NODE_TYPE_ELEMENT = 1;
1678 var NODE_TYPE_TEXT = 3;
1679 var NODE_TYPE_COMMENT = 8;
1680 var NODE_TYPE_DOCUMENT = 9;
1681 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1682
1683 /**
1684  * @ngdoc type
1685  * @name angular.Module
1686  * @module ng
1687  * @description
1688  *
1689  * Interface for configuring angular {@link angular.module modules}.
1690  */
1691
1692 function setupModuleLoader(window) {
1693
1694   var $injectorMinErr = minErr('$injector');
1695   var ngMinErr = minErr('ng');
1696
1697   function ensure(obj, name, factory) {
1698     return obj[name] || (obj[name] = factory());
1699   }
1700
1701   var angular = ensure(window, 'angular', Object);
1702
1703   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1704   angular.$$minErr = angular.$$minErr || minErr;
1705
1706   return ensure(angular, 'module', function() {
1707     /** @type {Object.<string, angular.Module>} */
1708     var modules = {};
1709
1710     /**
1711      * @ngdoc function
1712      * @name angular.module
1713      * @module ng
1714      * @description
1715      *
1716      * The `angular.module` is a global place for creating, registering and retrieving Angular
1717      * modules.
1718      * All modules (angular core or 3rd party) that should be available to an application must be
1719      * registered using this mechanism.
1720      *
1721      * When passed two or more arguments, a new module is created.  If passed only one argument, an
1722      * existing module (the name passed as the first argument to `module`) is retrieved.
1723      *
1724      *
1725      * # Module
1726      *
1727      * A module is a collection of services, directives, controllers, filters, and configuration information.
1728      * `angular.module` is used to configure the {@link auto.$injector $injector}.
1729      *
1730      * ```js
1731      * // Create a new module
1732      * var myModule = angular.module('myModule', []);
1733      *
1734      * // register a new service
1735      * myModule.value('appName', 'MyCoolApp');
1736      *
1737      * // configure existing services inside initialization blocks.
1738      * myModule.config(['$locationProvider', function($locationProvider) {
1739      *   // Configure existing providers
1740      *   $locationProvider.hashPrefix('!');
1741      * }]);
1742      * ```
1743      *
1744      * Then you can create an injector and load your modules like this:
1745      *
1746      * ```js
1747      * var injector = angular.injector(['ng', 'myModule'])
1748      * ```
1749      *
1750      * However it's more likely that you'll just use
1751      * {@link ng.directive:ngApp ngApp} or
1752      * {@link angular.bootstrap} to simplify this process for you.
1753      *
1754      * @param {!string} name The name of the module to create or retrieve.
1755      * @param {!Array.<string>=} requires If specified then new module is being created. If
1756      *        unspecified then the module is being retrieved for further configuration.
1757      * @param {Function=} configFn Optional configuration function for the module. Same as
1758      *        {@link angular.Module#config Module#config()}.
1759      * @returns {module} new module with the {@link angular.Module} api.
1760      */
1761     return function module(name, requires, configFn) {
1762       var assertNotHasOwnProperty = function(name, context) {
1763         if (name === 'hasOwnProperty') {
1764           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1765         }
1766       };
1767
1768       assertNotHasOwnProperty(name, 'module');
1769       if (requires && modules.hasOwnProperty(name)) {
1770         modules[name] = null;
1771       }
1772       return ensure(modules, name, function() {
1773         if (!requires) {
1774           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1775              "the module name or forgot to load it. If registering a module ensure that you " +
1776              "specify the dependencies as the second argument.", name);
1777         }
1778
1779         /** @type {!Array.<Array.<*>>} */
1780         var invokeQueue = [];
1781
1782         /** @type {!Array.<Function>} */
1783         var configBlocks = [];
1784
1785         /** @type {!Array.<Function>} */
1786         var runBlocks = [];
1787
1788         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
1789
1790         /** @type {angular.Module} */
1791         var moduleInstance = {
1792           // Private state
1793           _invokeQueue: invokeQueue,
1794           _configBlocks: configBlocks,
1795           _runBlocks: runBlocks,
1796
1797           /**
1798            * @ngdoc property
1799            * @name angular.Module#requires
1800            * @module ng
1801            *
1802            * @description
1803            * Holds the list of modules which the injector will load before the current module is
1804            * loaded.
1805            */
1806           requires: requires,
1807
1808           /**
1809            * @ngdoc property
1810            * @name angular.Module#name
1811            * @module ng
1812            *
1813            * @description
1814            * Name of the module.
1815            */
1816           name: name,
1817
1818
1819           /**
1820            * @ngdoc method
1821            * @name angular.Module#provider
1822            * @module ng
1823            * @param {string} name service name
1824            * @param {Function} providerType Construction function for creating new instance of the
1825            *                                service.
1826            * @description
1827            * See {@link auto.$provide#provider $provide.provider()}.
1828            */
1829           provider: invokeLater('$provide', 'provider'),
1830
1831           /**
1832            * @ngdoc method
1833            * @name angular.Module#factory
1834            * @module ng
1835            * @param {string} name service name
1836            * @param {Function} providerFunction Function for creating new instance of the service.
1837            * @description
1838            * See {@link auto.$provide#factory $provide.factory()}.
1839            */
1840           factory: invokeLater('$provide', 'factory'),
1841
1842           /**
1843            * @ngdoc method
1844            * @name angular.Module#service
1845            * @module ng
1846            * @param {string} name service name
1847            * @param {Function} constructor A constructor function that will be instantiated.
1848            * @description
1849            * See {@link auto.$provide#service $provide.service()}.
1850            */
1851           service: invokeLater('$provide', 'service'),
1852
1853           /**
1854            * @ngdoc method
1855            * @name angular.Module#value
1856            * @module ng
1857            * @param {string} name service name
1858            * @param {*} object Service instance object.
1859            * @description
1860            * See {@link auto.$provide#value $provide.value()}.
1861            */
1862           value: invokeLater('$provide', 'value'),
1863
1864           /**
1865            * @ngdoc method
1866            * @name angular.Module#constant
1867            * @module ng
1868            * @param {string} name constant name
1869            * @param {*} object Constant value.
1870            * @description
1871            * Because the constant are fixed, they get applied before other provide methods.
1872            * See {@link auto.$provide#constant $provide.constant()}.
1873            */
1874           constant: invokeLater('$provide', 'constant', 'unshift'),
1875
1876           /**
1877            * @ngdoc method
1878            * @name angular.Module#animation
1879            * @module ng
1880            * @param {string} name animation name
1881            * @param {Function} animationFactory Factory function for creating new instance of an
1882            *                                    animation.
1883            * @description
1884            *
1885            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1886            *
1887            *
1888            * Defines an animation hook that can be later used with
1889            * {@link ngAnimate.$animate $animate} service and directives that use this service.
1890            *
1891            * ```js
1892            * module.animation('.animation-name', function($inject1, $inject2) {
1893            *   return {
1894            *     eventName : function(element, done) {
1895            *       //code to run the animation
1896            *       //once complete, then run done()
1897            *       return function cancellationFunction(element) {
1898            *         //code to cancel the animation
1899            *       }
1900            *     }
1901            *   }
1902            * })
1903            * ```
1904            *
1905            * See {@link ng.$animateProvider#register $animateProvider.register()} and
1906            * {@link ngAnimate ngAnimate module} for more information.
1907            */
1908           animation: invokeLater('$animateProvider', 'register'),
1909
1910           /**
1911            * @ngdoc method
1912            * @name angular.Module#filter
1913            * @module ng
1914            * @param {string} name Filter name.
1915            * @param {Function} filterFactory Factory function for creating new instance of filter.
1916            * @description
1917            * See {@link ng.$filterProvider#register $filterProvider.register()}.
1918            */
1919           filter: invokeLater('$filterProvider', 'register'),
1920
1921           /**
1922            * @ngdoc method
1923            * @name angular.Module#controller
1924            * @module ng
1925            * @param {string|Object} name Controller name, or an object map of controllers where the
1926            *    keys are the names and the values are the constructors.
1927            * @param {Function} constructor Controller constructor function.
1928            * @description
1929            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1930            */
1931           controller: invokeLater('$controllerProvider', 'register'),
1932
1933           /**
1934            * @ngdoc method
1935            * @name angular.Module#directive
1936            * @module ng
1937            * @param {string|Object} name Directive name, or an object map of directives where the
1938            *    keys are the names and the values are the factories.
1939            * @param {Function} directiveFactory Factory function for creating new instance of
1940            * directives.
1941            * @description
1942            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1943            */
1944           directive: invokeLater('$compileProvider', 'directive'),
1945
1946           /**
1947            * @ngdoc method
1948            * @name angular.Module#config
1949            * @module ng
1950            * @param {Function} configFn Execute this function on module load. Useful for service
1951            *    configuration.
1952            * @description
1953            * Use this method to register work which needs to be performed on module loading.
1954            * For more about how to configure services, see
1955            * {@link providers#provider-recipe Provider Recipe}.
1956            */
1957           config: config,
1958
1959           /**
1960            * @ngdoc method
1961            * @name angular.Module#run
1962            * @module ng
1963            * @param {Function} initializationFn Execute this function after injector creation.
1964            *    Useful for application initialization.
1965            * @description
1966            * Use this method to register work which should be performed when the injector is done
1967            * loading all modules.
1968            */
1969           run: function(block) {
1970             runBlocks.push(block);
1971             return this;
1972           }
1973         };
1974
1975         if (configFn) {
1976           config(configFn);
1977         }
1978
1979         return moduleInstance;
1980
1981         /**
1982          * @param {string} provider
1983          * @param {string} method
1984          * @param {String=} insertMethod
1985          * @returns {angular.Module}
1986          */
1987         function invokeLater(provider, method, insertMethod, queue) {
1988           if (!queue) queue = invokeQueue;
1989           return function() {
1990             queue[insertMethod || 'push']([provider, method, arguments]);
1991             return moduleInstance;
1992           };
1993         }
1994       });
1995     };
1996   });
1997
1998 }
1999
2000 /* global: toDebugString: true */
2001
2002 function serializeObject(obj) {
2003   var seen = [];
2004
2005   return JSON.stringify(obj, function(key, val) {
2006     val = toJsonReplacer(key, val);
2007     if (isObject(val)) {
2008
2009       if (seen.indexOf(val) >= 0) return '<<already seen>>';
2010
2011       seen.push(val);
2012     }
2013     return val;
2014   });
2015 }
2016
2017 function toDebugString(obj) {
2018   if (typeof obj === 'function') {
2019     return obj.toString().replace(/ \{[\s\S]*$/, '');
2020   } else if (typeof obj === 'undefined') {
2021     return 'undefined';
2022   } else if (typeof obj !== 'string') {
2023     return serializeObject(obj);
2024   }
2025   return obj;
2026 }
2027
2028 /* global angularModule: true,
2029   version: true,
2030
2031   $LocaleProvider,
2032   $CompileProvider,
2033
2034   htmlAnchorDirective,
2035   inputDirective,
2036   inputDirective,
2037   formDirective,
2038   scriptDirective,
2039   selectDirective,
2040   styleDirective,
2041   optionDirective,
2042   ngBindDirective,
2043   ngBindHtmlDirective,
2044   ngBindTemplateDirective,
2045   ngClassDirective,
2046   ngClassEvenDirective,
2047   ngClassOddDirective,
2048   ngCspDirective,
2049   ngCloakDirective,
2050   ngControllerDirective,
2051   ngFormDirective,
2052   ngHideDirective,
2053   ngIfDirective,
2054   ngIncludeDirective,
2055   ngIncludeFillContentDirective,
2056   ngInitDirective,
2057   ngNonBindableDirective,
2058   ngPluralizeDirective,
2059   ngRepeatDirective,
2060   ngShowDirective,
2061   ngStyleDirective,
2062   ngSwitchDirective,
2063   ngSwitchWhenDirective,
2064   ngSwitchDefaultDirective,
2065   ngOptionsDirective,
2066   ngTranscludeDirective,
2067   ngModelDirective,
2068   ngListDirective,
2069   ngChangeDirective,
2070   patternDirective,
2071   patternDirective,
2072   requiredDirective,
2073   requiredDirective,
2074   minlengthDirective,
2075   minlengthDirective,
2076   maxlengthDirective,
2077   maxlengthDirective,
2078   ngValueDirective,
2079   ngModelOptionsDirective,
2080   ngAttributeAliasDirectives,
2081   ngEventDirectives,
2082
2083   $AnchorScrollProvider,
2084   $AnimateProvider,
2085   $BrowserProvider,
2086   $CacheFactoryProvider,
2087   $ControllerProvider,
2088   $DocumentProvider,
2089   $ExceptionHandlerProvider,
2090   $FilterProvider,
2091   $InterpolateProvider,
2092   $IntervalProvider,
2093   $HttpProvider,
2094   $HttpBackendProvider,
2095   $LocationProvider,
2096   $LogProvider,
2097   $ParseProvider,
2098   $RootScopeProvider,
2099   $QProvider,
2100   $$QProvider,
2101   $$SanitizeUriProvider,
2102   $SceProvider,
2103   $SceDelegateProvider,
2104   $SnifferProvider,
2105   $TemplateCacheProvider,
2106   $TemplateRequestProvider,
2107   $$TestabilityProvider,
2108   $TimeoutProvider,
2109   $$RAFProvider,
2110   $$AsyncCallbackProvider,
2111   $WindowProvider,
2112   $$jqLiteProvider
2113 */
2114
2115
2116 /**
2117  * @ngdoc object
2118  * @name angular.version
2119  * @module ng
2120  * @description
2121  * An object that contains information about the current AngularJS version. This object has the
2122  * following properties:
2123  *
2124  * - `full` – `{string}` – Full version string, such as "0.9.18".
2125  * - `major` – `{number}` – Major version number, such as "0".
2126  * - `minor` – `{number}` – Minor version number, such as "9".
2127  * - `dot` – `{number}` – Dot version number, such as "18".
2128  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2129  */
2130 var version = {
2131   full: '1.3.15',    // all of these placeholder strings will be replaced by grunt's
2132   major: 1,    // package task
2133   minor: 3,
2134   dot: 15,
2135   codeName: 'locality-filtration'
2136 };
2137
2138
2139 function publishExternalAPI(angular) {
2140   extend(angular, {
2141     'bootstrap': bootstrap,
2142     'copy': copy,
2143     'extend': extend,
2144     'equals': equals,
2145     'element': jqLite,
2146     'forEach': forEach,
2147     'injector': createInjector,
2148     'noop': noop,
2149     'bind': bind,
2150     'toJson': toJson,
2151     'fromJson': fromJson,
2152     'identity': identity,
2153     'isUndefined': isUndefined,
2154     'isDefined': isDefined,
2155     'isString': isString,
2156     'isFunction': isFunction,
2157     'isObject': isObject,
2158     'isNumber': isNumber,
2159     'isElement': isElement,
2160     'isArray': isArray,
2161     'version': version,
2162     'isDate': isDate,
2163     'lowercase': lowercase,
2164     'uppercase': uppercase,
2165     'callbacks': {counter: 0},
2166     'getTestability': getTestability,
2167     '$$minErr': minErr,
2168     '$$csp': csp,
2169     'reloadWithDebugInfo': reloadWithDebugInfo
2170   });
2171
2172   angularModule = setupModuleLoader(window);
2173   try {
2174     angularModule('ngLocale');
2175   } catch (e) {
2176     angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2177   }
2178
2179   angularModule('ng', ['ngLocale'], ['$provide',
2180     function ngModule($provide) {
2181       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2182       $provide.provider({
2183         $$sanitizeUri: $$SanitizeUriProvider
2184       });
2185       $provide.provider('$compile', $CompileProvider).
2186         directive({
2187             a: htmlAnchorDirective,
2188             input: inputDirective,
2189             textarea: inputDirective,
2190             form: formDirective,
2191             script: scriptDirective,
2192             select: selectDirective,
2193             style: styleDirective,
2194             option: optionDirective,
2195             ngBind: ngBindDirective,
2196             ngBindHtml: ngBindHtmlDirective,
2197             ngBindTemplate: ngBindTemplateDirective,
2198             ngClass: ngClassDirective,
2199             ngClassEven: ngClassEvenDirective,
2200             ngClassOdd: ngClassOddDirective,
2201             ngCloak: ngCloakDirective,
2202             ngController: ngControllerDirective,
2203             ngForm: ngFormDirective,
2204             ngHide: ngHideDirective,
2205             ngIf: ngIfDirective,
2206             ngInclude: ngIncludeDirective,
2207             ngInit: ngInitDirective,
2208             ngNonBindable: ngNonBindableDirective,
2209             ngPluralize: ngPluralizeDirective,
2210             ngRepeat: ngRepeatDirective,
2211             ngShow: ngShowDirective,
2212             ngStyle: ngStyleDirective,
2213             ngSwitch: ngSwitchDirective,
2214             ngSwitchWhen: ngSwitchWhenDirective,
2215             ngSwitchDefault: ngSwitchDefaultDirective,
2216             ngOptions: ngOptionsDirective,
2217             ngTransclude: ngTranscludeDirective,
2218             ngModel: ngModelDirective,
2219             ngList: ngListDirective,
2220             ngChange: ngChangeDirective,
2221             pattern: patternDirective,
2222             ngPattern: patternDirective,
2223             required: requiredDirective,
2224             ngRequired: requiredDirective,
2225             minlength: minlengthDirective,
2226             ngMinlength: minlengthDirective,
2227             maxlength: maxlengthDirective,
2228             ngMaxlength: maxlengthDirective,
2229             ngValue: ngValueDirective,
2230             ngModelOptions: ngModelOptionsDirective
2231         }).
2232         directive({
2233           ngInclude: ngIncludeFillContentDirective
2234         }).
2235         directive(ngAttributeAliasDirectives).
2236         directive(ngEventDirectives);
2237       $provide.provider({
2238         $anchorScroll: $AnchorScrollProvider,
2239         $animate: $AnimateProvider,
2240         $browser: $BrowserProvider,
2241         $cacheFactory: $CacheFactoryProvider,
2242         $controller: $ControllerProvider,
2243         $document: $DocumentProvider,
2244         $exceptionHandler: $ExceptionHandlerProvider,
2245         $filter: $FilterProvider,
2246         $interpolate: $InterpolateProvider,
2247         $interval: $IntervalProvider,
2248         $http: $HttpProvider,
2249         $httpBackend: $HttpBackendProvider,
2250         $location: $LocationProvider,
2251         $log: $LogProvider,
2252         $parse: $ParseProvider,
2253         $rootScope: $RootScopeProvider,
2254         $q: $QProvider,
2255         $$q: $$QProvider,
2256         $sce: $SceProvider,
2257         $sceDelegate: $SceDelegateProvider,
2258         $sniffer: $SnifferProvider,
2259         $templateCache: $TemplateCacheProvider,
2260         $templateRequest: $TemplateRequestProvider,
2261         $$testability: $$TestabilityProvider,
2262         $timeout: $TimeoutProvider,
2263         $window: $WindowProvider,
2264         $$rAF: $$RAFProvider,
2265         $$asyncCallback: $$AsyncCallbackProvider,
2266         $$jqLite: $$jqLiteProvider
2267       });
2268     }
2269   ]);
2270 }
2271
2272 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2273  *     Any commits to this file should be reviewed with security in mind.  *
2274  *   Changes to this file can potentially create security vulnerabilities. *
2275  *          An approval from 2 Core members with history of modifying      *
2276  *                         this file is required.                          *
2277  *                                                                         *
2278  *  Does the change somehow allow for arbitrary javascript to be executed? *
2279  *    Or allows for someone to change the prototype of built-in objects?   *
2280  *     Or gives undesired access to variables likes document or window?    *
2281  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2282
2283 /* global JQLitePrototype: true,
2284   addEventListenerFn: true,
2285   removeEventListenerFn: true,
2286   BOOLEAN_ATTR: true,
2287   ALIASED_ATTR: true,
2288 */
2289
2290 //////////////////////////////////
2291 //JQLite
2292 //////////////////////////////////
2293
2294 /**
2295  * @ngdoc function
2296  * @name angular.element
2297  * @module ng
2298  * @kind function
2299  *
2300  * @description
2301  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2302  *
2303  * If jQuery is available, `angular.element` is an alias for the
2304  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2305  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2306  *
2307  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2308  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2309  * commonly needed functionality with the goal of having a very small footprint.</div>
2310  *
2311  * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2312  *
2313  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2314  * jqLite; they are never raw DOM references.</div>
2315  *
2316  * ## Angular's jqLite
2317  * jqLite provides only the following jQuery methods:
2318  *
2319  * - [`addClass()`](http://api.jquery.com/addClass/)
2320  * - [`after()`](http://api.jquery.com/after/)
2321  * - [`append()`](http://api.jquery.com/append/)
2322  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2323  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2324  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2325  * - [`clone()`](http://api.jquery.com/clone/)
2326  * - [`contents()`](http://api.jquery.com/contents/)
2327  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`
2328  * - [`data()`](http://api.jquery.com/data/)
2329  * - [`detach()`](http://api.jquery.com/detach/)
2330  * - [`empty()`](http://api.jquery.com/empty/)
2331  * - [`eq()`](http://api.jquery.com/eq/)
2332  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2333  * - [`hasClass()`](http://api.jquery.com/hasClass/)
2334  * - [`html()`](http://api.jquery.com/html/)
2335  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2336  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2337  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2338  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2339  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2340  * - [`prepend()`](http://api.jquery.com/prepend/)
2341  * - [`prop()`](http://api.jquery.com/prop/)
2342  * - [`ready()`](http://api.jquery.com/ready/)
2343  * - [`remove()`](http://api.jquery.com/remove/)
2344  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2345  * - [`removeClass()`](http://api.jquery.com/removeClass/)
2346  * - [`removeData()`](http://api.jquery.com/removeData/)
2347  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2348  * - [`text()`](http://api.jquery.com/text/)
2349  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2350  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2351  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2352  * - [`val()`](http://api.jquery.com/val/)
2353  * - [`wrap()`](http://api.jquery.com/wrap/)
2354  *
2355  * ## jQuery/jqLite Extras
2356  * Angular also provides the following additional methods and events to both jQuery and jqLite:
2357  *
2358  * ### Events
2359  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2360  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2361  *    element before it is removed.
2362  *
2363  * ### Methods
2364  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2365  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2366  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2367  *   `'ngModel'`).
2368  * - `injector()` - retrieves the injector of the current element or its parent.
2369  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2370  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2371  *   be enabled.
2372  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2373  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2374  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2375  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2376  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2377  *   parent element is reached.
2378  *
2379  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2380  * @returns {Object} jQuery object.
2381  */
2382
2383 JQLite.expando = 'ng339';
2384
2385 var jqCache = JQLite.cache = {},
2386     jqId = 1,
2387     addEventListenerFn = function(element, type, fn) {
2388       element.addEventListener(type, fn, false);
2389     },
2390     removeEventListenerFn = function(element, type, fn) {
2391       element.removeEventListener(type, fn, false);
2392     };
2393
2394 /*
2395  * !!! This is an undocumented "private" function !!!
2396  */
2397 JQLite._data = function(node) {
2398   //jQuery always returns an object on cache miss
2399   return this.cache[node[this.expando]] || {};
2400 };
2401
2402 function jqNextId() { return ++jqId; }
2403
2404
2405 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2406 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2407 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2408 var jqLiteMinErr = minErr('jqLite');
2409
2410 /**
2411  * Converts snake_case to camelCase.
2412  * Also there is special case for Moz prefix starting with upper case letter.
2413  * @param name Name to normalize
2414  */
2415 function camelCase(name) {
2416   return name.
2417     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2418       return offset ? letter.toUpperCase() : letter;
2419     }).
2420     replace(MOZ_HACK_REGEXP, 'Moz$1');
2421 }
2422
2423 var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2424 var HTML_REGEXP = /<|&#?\w+;/;
2425 var TAG_NAME_REGEXP = /<([\w:]+)/;
2426 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2427
2428 var wrapMap = {
2429   'option': [1, '<select multiple="multiple">', '</select>'],
2430
2431   'thead': [1, '<table>', '</table>'],
2432   'col': [2, '<table><colgroup>', '</colgroup></table>'],
2433   'tr': [2, '<table><tbody>', '</tbody></table>'],
2434   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2435   '_default': [0, "", ""]
2436 };
2437
2438 wrapMap.optgroup = wrapMap.option;
2439 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2440 wrapMap.th = wrapMap.td;
2441
2442
2443 function jqLiteIsTextNode(html) {
2444   return !HTML_REGEXP.test(html);
2445 }
2446
2447 function jqLiteAcceptsData(node) {
2448   // The window object can accept data but has no nodeType
2449   // Otherwise we are only interested in elements (1) and documents (9)
2450   var nodeType = node.nodeType;
2451   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2452 }
2453
2454 function jqLiteBuildFragment(html, context) {
2455   var tmp, tag, wrap,
2456       fragment = context.createDocumentFragment(),
2457       nodes = [], i;
2458
2459   if (jqLiteIsTextNode(html)) {
2460     // Convert non-html into a text node
2461     nodes.push(context.createTextNode(html));
2462   } else {
2463     // Convert html into DOM nodes
2464     tmp = tmp || fragment.appendChild(context.createElement("div"));
2465     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2466     wrap = wrapMap[tag] || wrapMap._default;
2467     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2468
2469     // Descend through wrappers to the right content
2470     i = wrap[0];
2471     while (i--) {
2472       tmp = tmp.lastChild;
2473     }
2474
2475     nodes = concat(nodes, tmp.childNodes);
2476
2477     tmp = fragment.firstChild;
2478     tmp.textContent = "";
2479   }
2480
2481   // Remove wrapper from fragment
2482   fragment.textContent = "";
2483   fragment.innerHTML = ""; // Clear inner HTML
2484   forEach(nodes, function(node) {
2485     fragment.appendChild(node);
2486   });
2487
2488   return fragment;
2489 }
2490
2491 function jqLiteParseHTML(html, context) {
2492   context = context || document;
2493   var parsed;
2494
2495   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2496     return [context.createElement(parsed[1])];
2497   }
2498
2499   if ((parsed = jqLiteBuildFragment(html, context))) {
2500     return parsed.childNodes;
2501   }
2502
2503   return [];
2504 }
2505
2506 /////////////////////////////////////////////
2507 function JQLite(element) {
2508   if (element instanceof JQLite) {
2509     return element;
2510   }
2511
2512   var argIsString;
2513
2514   if (isString(element)) {
2515     element = trim(element);
2516     argIsString = true;
2517   }
2518   if (!(this instanceof JQLite)) {
2519     if (argIsString && element.charAt(0) != '<') {
2520       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2521     }
2522     return new JQLite(element);
2523   }
2524
2525   if (argIsString) {
2526     jqLiteAddNodes(this, jqLiteParseHTML(element));
2527   } else {
2528     jqLiteAddNodes(this, element);
2529   }
2530 }
2531
2532 function jqLiteClone(element) {
2533   return element.cloneNode(true);
2534 }
2535
2536 function jqLiteDealoc(element, onlyDescendants) {
2537   if (!onlyDescendants) jqLiteRemoveData(element);
2538
2539   if (element.querySelectorAll) {
2540     var descendants = element.querySelectorAll('*');
2541     for (var i = 0, l = descendants.length; i < l; i++) {
2542       jqLiteRemoveData(descendants[i]);
2543     }
2544   }
2545 }
2546
2547 function jqLiteOff(element, type, fn, unsupported) {
2548   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2549
2550   var expandoStore = jqLiteExpandoStore(element);
2551   var events = expandoStore && expandoStore.events;
2552   var handle = expandoStore && expandoStore.handle;
2553
2554   if (!handle) return; //no listeners registered
2555
2556   if (!type) {
2557     for (type in events) {
2558       if (type !== '$destroy') {
2559         removeEventListenerFn(element, type, handle);
2560       }
2561       delete events[type];
2562     }
2563   } else {
2564     forEach(type.split(' '), function(type) {
2565       if (isDefined(fn)) {
2566         var listenerFns = events[type];
2567         arrayRemove(listenerFns || [], fn);
2568         if (listenerFns && listenerFns.length > 0) {
2569           return;
2570         }
2571       }
2572
2573       removeEventListenerFn(element, type, handle);
2574       delete events[type];
2575     });
2576   }
2577 }
2578
2579 function jqLiteRemoveData(element, name) {
2580   var expandoId = element.ng339;
2581   var expandoStore = expandoId && jqCache[expandoId];
2582
2583   if (expandoStore) {
2584     if (name) {
2585       delete expandoStore.data[name];
2586       return;
2587     }
2588
2589     if (expandoStore.handle) {
2590       if (expandoStore.events.$destroy) {
2591         expandoStore.handle({}, '$destroy');
2592       }
2593       jqLiteOff(element);
2594     }
2595     delete jqCache[expandoId];
2596     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2597   }
2598 }
2599
2600
2601 function jqLiteExpandoStore(element, createIfNecessary) {
2602   var expandoId = element.ng339,
2603       expandoStore = expandoId && jqCache[expandoId];
2604
2605   if (createIfNecessary && !expandoStore) {
2606     element.ng339 = expandoId = jqNextId();
2607     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2608   }
2609
2610   return expandoStore;
2611 }
2612
2613
2614 function jqLiteData(element, key, value) {
2615   if (jqLiteAcceptsData(element)) {
2616
2617     var isSimpleSetter = isDefined(value);
2618     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2619     var massGetter = !key;
2620     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2621     var data = expandoStore && expandoStore.data;
2622
2623     if (isSimpleSetter) { // data('key', value)
2624       data[key] = value;
2625     } else {
2626       if (massGetter) {  // data()
2627         return data;
2628       } else {
2629         if (isSimpleGetter) { // data('key')
2630           // don't force creation of expandoStore if it doesn't exist yet
2631           return data && data[key];
2632         } else { // mass-setter: data({key1: val1, key2: val2})
2633           extend(data, key);
2634         }
2635       }
2636     }
2637   }
2638 }
2639
2640 function jqLiteHasClass(element, selector) {
2641   if (!element.getAttribute) return false;
2642   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2643       indexOf(" " + selector + " ") > -1);
2644 }
2645
2646 function jqLiteRemoveClass(element, cssClasses) {
2647   if (cssClasses && element.setAttribute) {
2648     forEach(cssClasses.split(' '), function(cssClass) {
2649       element.setAttribute('class', trim(
2650           (" " + (element.getAttribute('class') || '') + " ")
2651           .replace(/[\n\t]/g, " ")
2652           .replace(" " + trim(cssClass) + " ", " "))
2653       );
2654     });
2655   }
2656 }
2657
2658 function jqLiteAddClass(element, cssClasses) {
2659   if (cssClasses && element.setAttribute) {
2660     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2661                             .replace(/[\n\t]/g, " ");
2662
2663     forEach(cssClasses.split(' '), function(cssClass) {
2664       cssClass = trim(cssClass);
2665       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2666         existingClasses += cssClass + ' ';
2667       }
2668     });
2669
2670     element.setAttribute('class', trim(existingClasses));
2671   }
2672 }
2673
2674
2675 function jqLiteAddNodes(root, elements) {
2676   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
2677
2678   if (elements) {
2679
2680     // if a Node (the most common case)
2681     if (elements.nodeType) {
2682       root[root.length++] = elements;
2683     } else {
2684       var length = elements.length;
2685
2686       // if an Array or NodeList and not a Window
2687       if (typeof length === 'number' && elements.window !== elements) {
2688         if (length) {
2689           for (var i = 0; i < length; i++) {
2690             root[root.length++] = elements[i];
2691           }
2692         }
2693       } else {
2694         root[root.length++] = elements;
2695       }
2696     }
2697   }
2698 }
2699
2700
2701 function jqLiteController(element, name) {
2702   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
2703 }
2704
2705 function jqLiteInheritedData(element, name, value) {
2706   // if element is the document object work with the html element instead
2707   // this makes $(document).scope() possible
2708   if (element.nodeType == NODE_TYPE_DOCUMENT) {
2709     element = element.documentElement;
2710   }
2711   var names = isArray(name) ? name : [name];
2712
2713   while (element) {
2714     for (var i = 0, ii = names.length; i < ii; i++) {
2715       if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2716     }
2717
2718     // If dealing with a document fragment node with a host element, and no parent, use the host
2719     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2720     // to lookup parent controllers.
2721     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
2722   }
2723 }
2724
2725 function jqLiteEmpty(element) {
2726   jqLiteDealoc(element, true);
2727   while (element.firstChild) {
2728     element.removeChild(element.firstChild);
2729   }
2730 }
2731
2732 function jqLiteRemove(element, keepData) {
2733   if (!keepData) jqLiteDealoc(element);
2734   var parent = element.parentNode;
2735   if (parent) parent.removeChild(element);
2736 }
2737
2738
2739 function jqLiteDocumentLoaded(action, win) {
2740   win = win || window;
2741   if (win.document.readyState === 'complete') {
2742     // Force the action to be run async for consistent behaviour
2743     // from the action's point of view
2744     // i.e. it will definitely not be in a $apply
2745     win.setTimeout(action);
2746   } else {
2747     // No need to unbind this handler as load is only ever called once
2748     jqLite(win).on('load', action);
2749   }
2750 }
2751
2752 //////////////////////////////////////////
2753 // Functions which are declared directly.
2754 //////////////////////////////////////////
2755 var JQLitePrototype = JQLite.prototype = {
2756   ready: function(fn) {
2757     var fired = false;
2758
2759     function trigger() {
2760       if (fired) return;
2761       fired = true;
2762       fn();
2763     }
2764
2765     // check if document is already loaded
2766     if (document.readyState === 'complete') {
2767       setTimeout(trigger);
2768     } else {
2769       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2770       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2771       // jshint -W064
2772       JQLite(window).on('load', trigger); // fallback to window.onload for others
2773       // jshint +W064
2774     }
2775   },
2776   toString: function() {
2777     var value = [];
2778     forEach(this, function(e) { value.push('' + e);});
2779     return '[' + value.join(', ') + ']';
2780   },
2781
2782   eq: function(index) {
2783       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2784   },
2785
2786   length: 0,
2787   push: push,
2788   sort: [].sort,
2789   splice: [].splice
2790 };
2791
2792 //////////////////////////////////////////
2793 // Functions iterating getter/setters.
2794 // these functions return self on setter and
2795 // value on get.
2796 //////////////////////////////////////////
2797 var BOOLEAN_ATTR = {};
2798 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2799   BOOLEAN_ATTR[lowercase(value)] = value;
2800 });
2801 var BOOLEAN_ELEMENTS = {};
2802 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2803   BOOLEAN_ELEMENTS[value] = true;
2804 });
2805 var ALIASED_ATTR = {
2806   'ngMinlength': 'minlength',
2807   'ngMaxlength': 'maxlength',
2808   'ngMin': 'min',
2809   'ngMax': 'max',
2810   'ngPattern': 'pattern'
2811 };
2812
2813 function getBooleanAttrName(element, name) {
2814   // check dom last since we will most likely fail on name
2815   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2816
2817   // booleanAttr is here twice to minimize DOM access
2818   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
2819 }
2820
2821 function getAliasedAttrName(element, name) {
2822   var nodeName = element.nodeName;
2823   return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
2824 }
2825
2826 forEach({
2827   data: jqLiteData,
2828   removeData: jqLiteRemoveData
2829 }, function(fn, name) {
2830   JQLite[name] = fn;
2831 });
2832
2833 forEach({
2834   data: jqLiteData,
2835   inheritedData: jqLiteInheritedData,
2836
2837   scope: function(element) {
2838     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2839     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2840   },
2841
2842   isolateScope: function(element) {
2843     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2844     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2845   },
2846
2847   controller: jqLiteController,
2848
2849   injector: function(element) {
2850     return jqLiteInheritedData(element, '$injector');
2851   },
2852
2853   removeAttr: function(element, name) {
2854     element.removeAttribute(name);
2855   },
2856
2857   hasClass: jqLiteHasClass,
2858
2859   css: function(element, name, value) {
2860     name = camelCase(name);
2861
2862     if (isDefined(value)) {
2863       element.style[name] = value;
2864     } else {
2865       return element.style[name];
2866     }
2867   },
2868
2869   attr: function(element, name, value) {
2870     var lowercasedName = lowercase(name);
2871     if (BOOLEAN_ATTR[lowercasedName]) {
2872       if (isDefined(value)) {
2873         if (!!value) {
2874           element[name] = true;
2875           element.setAttribute(name, lowercasedName);
2876         } else {
2877           element[name] = false;
2878           element.removeAttribute(lowercasedName);
2879         }
2880       } else {
2881         return (element[name] ||
2882                  (element.attributes.getNamedItem(name) || noop).specified)
2883                ? lowercasedName
2884                : undefined;
2885       }
2886     } else if (isDefined(value)) {
2887       element.setAttribute(name, value);
2888     } else if (element.getAttribute) {
2889       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2890       // some elements (e.g. Document) don't have get attribute, so return undefined
2891       var ret = element.getAttribute(name, 2);
2892       // normalize non-existing attributes to undefined (as jQuery)
2893       return ret === null ? undefined : ret;
2894     }
2895   },
2896
2897   prop: function(element, name, value) {
2898     if (isDefined(value)) {
2899       element[name] = value;
2900     } else {
2901       return element[name];
2902     }
2903   },
2904
2905   text: (function() {
2906     getText.$dv = '';
2907     return getText;
2908
2909     function getText(element, value) {
2910       if (isUndefined(value)) {
2911         var nodeType = element.nodeType;
2912         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
2913       }
2914       element.textContent = value;
2915     }
2916   })(),
2917
2918   val: function(element, value) {
2919     if (isUndefined(value)) {
2920       if (element.multiple && nodeName_(element) === 'select') {
2921         var result = [];
2922         forEach(element.options, function(option) {
2923           if (option.selected) {
2924             result.push(option.value || option.text);
2925           }
2926         });
2927         return result.length === 0 ? null : result;
2928       }
2929       return element.value;
2930     }
2931     element.value = value;
2932   },
2933
2934   html: function(element, value) {
2935     if (isUndefined(value)) {
2936       return element.innerHTML;
2937     }
2938     jqLiteDealoc(element, true);
2939     element.innerHTML = value;
2940   },
2941
2942   empty: jqLiteEmpty
2943 }, function(fn, name) {
2944   /**
2945    * Properties: writes return selection, reads return first value
2946    */
2947   JQLite.prototype[name] = function(arg1, arg2) {
2948     var i, key;
2949     var nodeCount = this.length;
2950
2951     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2952     // in a way that survives minification.
2953     // jqLiteEmpty takes no arguments but is a setter.
2954     if (fn !== jqLiteEmpty &&
2955         (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2956       if (isObject(arg1)) {
2957
2958         // we are a write, but the object properties are the key/values
2959         for (i = 0; i < nodeCount; i++) {
2960           if (fn === jqLiteData) {
2961             // data() takes the whole object in jQuery
2962             fn(this[i], arg1);
2963           } else {
2964             for (key in arg1) {
2965               fn(this[i], key, arg1[key]);
2966             }
2967           }
2968         }
2969         // return self for chaining
2970         return this;
2971       } else {
2972         // we are a read, so read the first child.
2973         // TODO: do we still need this?
2974         var value = fn.$dv;
2975         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2976         var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2977         for (var j = 0; j < jj; j++) {
2978           var nodeValue = fn(this[j], arg1, arg2);
2979           value = value ? value + nodeValue : nodeValue;
2980         }
2981         return value;
2982       }
2983     } else {
2984       // we are a write, so apply to all children
2985       for (i = 0; i < nodeCount; i++) {
2986         fn(this[i], arg1, arg2);
2987       }
2988       // return self for chaining
2989       return this;
2990     }
2991   };
2992 });
2993
2994 function createEventHandler(element, events) {
2995   var eventHandler = function(event, type) {
2996     // jQuery specific api
2997     event.isDefaultPrevented = function() {
2998       return event.defaultPrevented;
2999     };
3000
3001     var eventFns = events[type || event.type];
3002     var eventFnsLength = eventFns ? eventFns.length : 0;
3003
3004     if (!eventFnsLength) return;
3005
3006     if (isUndefined(event.immediatePropagationStopped)) {
3007       var originalStopImmediatePropagation = event.stopImmediatePropagation;
3008       event.stopImmediatePropagation = function() {
3009         event.immediatePropagationStopped = true;
3010
3011         if (event.stopPropagation) {
3012           event.stopPropagation();
3013         }
3014
3015         if (originalStopImmediatePropagation) {
3016           originalStopImmediatePropagation.call(event);
3017         }
3018       };
3019     }
3020
3021     event.isImmediatePropagationStopped = function() {
3022       return event.immediatePropagationStopped === true;
3023     };
3024
3025     // Copy event handlers in case event handlers array is modified during execution.
3026     if ((eventFnsLength > 1)) {
3027       eventFns = shallowCopy(eventFns);
3028     }
3029
3030     for (var i = 0; i < eventFnsLength; i++) {
3031       if (!event.isImmediatePropagationStopped()) {
3032         eventFns[i].call(element, event);
3033       }
3034     }
3035   };
3036
3037   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3038   //       events on `element`
3039   eventHandler.elem = element;
3040   return eventHandler;
3041 }
3042
3043 //////////////////////////////////////////
3044 // Functions iterating traversal.
3045 // These functions chain results into a single
3046 // selector.
3047 //////////////////////////////////////////
3048 forEach({
3049   removeData: jqLiteRemoveData,
3050
3051   on: function jqLiteOn(element, type, fn, unsupported) {
3052     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3053
3054     // Do not add event handlers to non-elements because they will not be cleaned up.
3055     if (!jqLiteAcceptsData(element)) {
3056       return;
3057     }
3058
3059     var expandoStore = jqLiteExpandoStore(element, true);
3060     var events = expandoStore.events;
3061     var handle = expandoStore.handle;
3062
3063     if (!handle) {
3064       handle = expandoStore.handle = createEventHandler(element, events);
3065     }
3066
3067     // http://jsperf.com/string-indexof-vs-split
3068     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3069     var i = types.length;
3070
3071     while (i--) {
3072       type = types[i];
3073       var eventFns = events[type];
3074
3075       if (!eventFns) {
3076         events[type] = [];
3077
3078         if (type === 'mouseenter' || type === 'mouseleave') {
3079           // Refer to jQuery's implementation of mouseenter & mouseleave
3080           // Read about mouseenter and mouseleave:
3081           // http://www.quirksmode.org/js/events_mouse.html#link8
3082
3083           jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
3084             var target = this, related = event.relatedTarget;
3085             // For mousenter/leave call the handler if related is outside the target.
3086             // NB: No relatedTarget if the mouse left/entered the browser window
3087             if (!related || (related !== target && !target.contains(related))) {
3088               handle(event, type);
3089             }
3090           });
3091
3092         } else {
3093           if (type !== '$destroy') {
3094             addEventListenerFn(element, type, handle);
3095           }
3096         }
3097         eventFns = events[type];
3098       }
3099       eventFns.push(fn);
3100     }
3101   },
3102
3103   off: jqLiteOff,
3104
3105   one: function(element, type, fn) {
3106     element = jqLite(element);
3107
3108     //add the listener twice so that when it is called
3109     //you can remove the original function and still be
3110     //able to call element.off(ev, fn) normally
3111     element.on(type, function onFn() {
3112       element.off(type, fn);
3113       element.off(type, onFn);
3114     });
3115     element.on(type, fn);
3116   },
3117
3118   replaceWith: function(element, replaceNode) {
3119     var index, parent = element.parentNode;
3120     jqLiteDealoc(element);
3121     forEach(new JQLite(replaceNode), function(node) {
3122       if (index) {
3123         parent.insertBefore(node, index.nextSibling);
3124       } else {
3125         parent.replaceChild(node, element);
3126       }
3127       index = node;
3128     });
3129   },
3130
3131   children: function(element) {
3132     var children = [];
3133     forEach(element.childNodes, function(element) {
3134       if (element.nodeType === NODE_TYPE_ELEMENT)
3135         children.push(element);
3136     });
3137     return children;
3138   },
3139
3140   contents: function(element) {
3141     return element.contentDocument || element.childNodes || [];
3142   },
3143
3144   append: function(element, node) {
3145     var nodeType = element.nodeType;
3146     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3147
3148     node = new JQLite(node);
3149
3150     for (var i = 0, ii = node.length; i < ii; i++) {
3151       var child = node[i];
3152       element.appendChild(child);
3153     }
3154   },
3155
3156   prepend: function(element, node) {
3157     if (element.nodeType === NODE_TYPE_ELEMENT) {
3158       var index = element.firstChild;
3159       forEach(new JQLite(node), function(child) {
3160         element.insertBefore(child, index);
3161       });
3162     }
3163   },
3164
3165   wrap: function(element, wrapNode) {
3166     wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3167     var parent = element.parentNode;
3168     if (parent) {
3169       parent.replaceChild(wrapNode, element);
3170     }
3171     wrapNode.appendChild(element);
3172   },
3173
3174   remove: jqLiteRemove,
3175
3176   detach: function(element) {
3177     jqLiteRemove(element, true);
3178   },
3179
3180   after: function(element, newElement) {
3181     var index = element, parent = element.parentNode;
3182     newElement = new JQLite(newElement);
3183
3184     for (var i = 0, ii = newElement.length; i < ii; i++) {
3185       var node = newElement[i];
3186       parent.insertBefore(node, index.nextSibling);
3187       index = node;
3188     }
3189   },
3190
3191   addClass: jqLiteAddClass,
3192   removeClass: jqLiteRemoveClass,
3193
3194   toggleClass: function(element, selector, condition) {
3195     if (selector) {
3196       forEach(selector.split(' '), function(className) {
3197         var classCondition = condition;
3198         if (isUndefined(classCondition)) {
3199           classCondition = !jqLiteHasClass(element, className);
3200         }
3201         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3202       });
3203     }
3204   },
3205
3206   parent: function(element) {
3207     var parent = element.parentNode;
3208     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3209   },
3210
3211   next: function(element) {
3212     return element.nextElementSibling;
3213   },
3214
3215   find: function(element, selector) {
3216     if (element.getElementsByTagName) {
3217       return element.getElementsByTagName(selector);
3218     } else {
3219       return [];
3220     }
3221   },
3222
3223   clone: jqLiteClone,
3224
3225   triggerHandler: function(element, event, extraParameters) {
3226
3227     var dummyEvent, eventFnsCopy, handlerArgs;
3228     var eventName = event.type || event;
3229     var expandoStore = jqLiteExpandoStore(element);
3230     var events = expandoStore && expandoStore.events;
3231     var eventFns = events && events[eventName];
3232
3233     if (eventFns) {
3234       // Create a dummy event to pass to the handlers
3235       dummyEvent = {
3236         preventDefault: function() { this.defaultPrevented = true; },
3237         isDefaultPrevented: function() { return this.defaultPrevented === true; },
3238         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3239         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3240         stopPropagation: noop,
3241         type: eventName,
3242         target: element
3243       };
3244
3245       // If a custom event was provided then extend our dummy event with it
3246       if (event.type) {
3247         dummyEvent = extend(dummyEvent, event);
3248       }
3249
3250       // Copy event handlers in case event handlers array is modified during execution.
3251       eventFnsCopy = shallowCopy(eventFns);
3252       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3253
3254       forEach(eventFnsCopy, function(fn) {
3255         if (!dummyEvent.isImmediatePropagationStopped()) {
3256           fn.apply(element, handlerArgs);
3257         }
3258       });
3259     }
3260   }
3261 }, function(fn, name) {
3262   /**
3263    * chaining functions
3264    */
3265   JQLite.prototype[name] = function(arg1, arg2, arg3) {
3266     var value;
3267
3268     for (var i = 0, ii = this.length; i < ii; i++) {
3269       if (isUndefined(value)) {
3270         value = fn(this[i], arg1, arg2, arg3);
3271         if (isDefined(value)) {
3272           // any function which returns a value needs to be wrapped
3273           value = jqLite(value);
3274         }
3275       } else {
3276         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3277       }
3278     }
3279     return isDefined(value) ? value : this;
3280   };
3281
3282   // bind legacy bind/unbind to on/off
3283   JQLite.prototype.bind = JQLite.prototype.on;
3284   JQLite.prototype.unbind = JQLite.prototype.off;
3285 });
3286
3287
3288 // Provider for private $$jqLite service
3289 function $$jqLiteProvider() {
3290   this.$get = function $$jqLite() {
3291     return extend(JQLite, {
3292       hasClass: function(node, classes) {
3293         if (node.attr) node = node[0];
3294         return jqLiteHasClass(node, classes);
3295       },
3296       addClass: function(node, classes) {
3297         if (node.attr) node = node[0];
3298         return jqLiteAddClass(node, classes);
3299       },
3300       removeClass: function(node, classes) {
3301         if (node.attr) node = node[0];
3302         return jqLiteRemoveClass(node, classes);
3303       }
3304     });
3305   };
3306 }
3307
3308 /**
3309  * Computes a hash of an 'obj'.
3310  * Hash of a:
3311  *  string is string
3312  *  number is number as string
3313  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3314  *         that is also assigned to the $$hashKey property of the object.
3315  *
3316  * @param obj
3317  * @returns {string} hash string such that the same input will have the same hash string.
3318  *         The resulting string key is in 'type:hashKey' format.
3319  */
3320 function hashKey(obj, nextUidFn) {
3321   var key = obj && obj.$$hashKey;
3322
3323   if (key) {
3324     if (typeof key === 'function') {
3325       key = obj.$$hashKey();
3326     }
3327     return key;
3328   }
3329
3330   var objType = typeof obj;
3331   if (objType == 'function' || (objType == 'object' && obj !== null)) {
3332     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3333   } else {
3334     key = objType + ':' + obj;
3335   }
3336
3337   return key;
3338 }
3339
3340 /**
3341  * HashMap which can use objects as keys
3342  */
3343 function HashMap(array, isolatedUid) {
3344   if (isolatedUid) {
3345     var uid = 0;
3346     this.nextUid = function() {
3347       return ++uid;
3348     };
3349   }
3350   forEach(array, this.put, this);
3351 }
3352 HashMap.prototype = {
3353   /**
3354    * Store key value pair
3355    * @param key key to store can be any type
3356    * @param value value to store can be any type
3357    */
3358   put: function(key, value) {
3359     this[hashKey(key, this.nextUid)] = value;
3360   },
3361
3362   /**
3363    * @param key
3364    * @returns {Object} the value for the key
3365    */
3366   get: function(key) {
3367     return this[hashKey(key, this.nextUid)];
3368   },
3369
3370   /**
3371    * Remove the key/value pair
3372    * @param key
3373    */
3374   remove: function(key) {
3375     var value = this[key = hashKey(key, this.nextUid)];
3376     delete this[key];
3377     return value;
3378   }
3379 };
3380
3381 /**
3382  * @ngdoc function
3383  * @module ng
3384  * @name angular.injector
3385  * @kind function
3386  *
3387  * @description
3388  * Creates an injector object that can be used for retrieving services as well as for
3389  * dependency injection (see {@link guide/di dependency injection}).
3390  *
3391  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3392  *     {@link angular.module}. The `ng` module must be explicitly added.
3393  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3394  *     disallows argument name annotation inference.
3395  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3396  *
3397  * @example
3398  * Typical usage
3399  * ```js
3400  *   // create an injector
3401  *   var $injector = angular.injector(['ng']);
3402  *
3403  *   // use the injector to kick off your application
3404  *   // use the type inference to auto inject arguments, or use implicit injection
3405  *   $injector.invoke(function($rootScope, $compile, $document) {
3406  *     $compile($document)($rootScope);
3407  *     $rootScope.$digest();
3408  *   });
3409  * ```
3410  *
3411  * Sometimes you want to get access to the injector of a currently running Angular app
3412  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3413  * application has been bootstrapped. You can do this using the extra `injector()` added
3414  * to JQuery/jqLite elements. See {@link angular.element}.
3415  *
3416  * *This is fairly rare but could be the case if a third party library is injecting the
3417  * markup.*
3418  *
3419  * In the following example a new block of HTML containing a `ng-controller`
3420  * directive is added to the end of the document body by JQuery. We then compile and link
3421  * it into the current AngularJS scope.
3422  *
3423  * ```js
3424  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3425  * $(document.body).append($div);
3426  *
3427  * angular.element(document).injector().invoke(function($compile) {
3428  *   var scope = angular.element($div).scope();
3429  *   $compile($div)(scope);
3430  * });
3431  * ```
3432  */
3433
3434
3435 /**
3436  * @ngdoc module
3437  * @name auto
3438  * @description
3439  *
3440  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3441  */
3442
3443 var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3444 var FN_ARG_SPLIT = /,/;
3445 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3446 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3447 var $injectorMinErr = minErr('$injector');
3448
3449 function anonFn(fn) {
3450   // For anonymous functions, showing at the very least the function signature can help in
3451   // debugging.
3452   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3453       args = fnText.match(FN_ARGS);
3454   if (args) {
3455     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3456   }
3457   return 'fn';
3458 }
3459
3460 function annotate(fn, strictDi, name) {
3461   var $inject,
3462       fnText,
3463       argDecl,
3464       last;
3465
3466   if (typeof fn === 'function') {
3467     if (!($inject = fn.$inject)) {
3468       $inject = [];
3469       if (fn.length) {
3470         if (strictDi) {
3471           if (!isString(name) || !name) {
3472             name = fn.name || anonFn(fn);
3473           }
3474           throw $injectorMinErr('strictdi',
3475             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3476         }
3477         fnText = fn.toString().replace(STRIP_COMMENTS, '');
3478         argDecl = fnText.match(FN_ARGS);
3479         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3480           arg.replace(FN_ARG, function(all, underscore, name) {
3481             $inject.push(name);
3482           });
3483         });
3484       }
3485       fn.$inject = $inject;
3486     }
3487   } else if (isArray(fn)) {
3488     last = fn.length - 1;
3489     assertArgFn(fn[last], 'fn');
3490     $inject = fn.slice(0, last);
3491   } else {
3492     assertArgFn(fn, 'fn', true);
3493   }
3494   return $inject;
3495 }
3496
3497 ///////////////////////////////////////
3498
3499 /**
3500  * @ngdoc service
3501  * @name $injector
3502  *
3503  * @description
3504  *
3505  * `$injector` is used to retrieve object instances as defined by
3506  * {@link auto.$provide provider}, instantiate types, invoke methods,
3507  * and load modules.
3508  *
3509  * The following always holds true:
3510  *
3511  * ```js
3512  *   var $injector = angular.injector();
3513  *   expect($injector.get('$injector')).toBe($injector);
3514  *   expect($injector.invoke(function($injector) {
3515  *     return $injector;
3516  *   })).toBe($injector);
3517  * ```
3518  *
3519  * # Injection Function Annotation
3520  *
3521  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3522  * following are all valid ways of annotating function with injection arguments and are equivalent.
3523  *
3524  * ```js
3525  *   // inferred (only works if code not minified/obfuscated)
3526  *   $injector.invoke(function(serviceA){});
3527  *
3528  *   // annotated
3529  *   function explicit(serviceA) {};
3530  *   explicit.$inject = ['serviceA'];
3531  *   $injector.invoke(explicit);
3532  *
3533  *   // inline
3534  *   $injector.invoke(['serviceA', function(serviceA){}]);
3535  * ```
3536  *
3537  * ## Inference
3538  *
3539  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3540  * can then be parsed and the function arguments can be extracted. This method of discovering
3541  * annotations is disallowed when the injector is in strict mode.
3542  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3543  * argument names.
3544  *
3545  * ## `$inject` Annotation
3546  * By adding an `$inject` property onto a function the injection parameters can be specified.
3547  *
3548  * ## Inline
3549  * As an array of injection names, where the last item in the array is the function to call.
3550  */
3551
3552 /**
3553  * @ngdoc method
3554  * @name $injector#get
3555  *
3556  * @description
3557  * Return an instance of the service.
3558  *
3559  * @param {string} name The name of the instance to retrieve.
3560  * @param {string} caller An optional string to provide the origin of the function call for error messages.
3561  * @return {*} The instance.
3562  */
3563
3564 /**
3565  * @ngdoc method
3566  * @name $injector#invoke
3567  *
3568  * @description
3569  * Invoke the method and supply the method arguments from the `$injector`.
3570  *
3571  * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3572  *   {@link guide/di $inject Annotation} rules.
3573  * @param {Object=} self The `this` for the invoked method.
3574  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3575  *                         object first, before the `$injector` is consulted.
3576  * @returns {*} the value returned by the invoked `fn` function.
3577  */
3578
3579 /**
3580  * @ngdoc method
3581  * @name $injector#has
3582  *
3583  * @description
3584  * Allows the user to query if the particular service exists.
3585  *
3586  * @param {string} name Name of the service to query.
3587  * @returns {boolean} `true` if injector has given service.
3588  */
3589
3590 /**
3591  * @ngdoc method
3592  * @name $injector#instantiate
3593  * @description
3594  * Create a new instance of JS type. The method takes a constructor function, invokes the new
3595  * operator, and supplies all of the arguments to the constructor function as specified by the
3596  * constructor annotation.
3597  *
3598  * @param {Function} Type Annotated constructor function.
3599  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3600  * object first, before the `$injector` is consulted.
3601  * @returns {Object} new instance of `Type`.
3602  */
3603
3604 /**
3605  * @ngdoc method
3606  * @name $injector#annotate
3607  *
3608  * @description
3609  * Returns an array of service names which the function is requesting for injection. This API is
3610  * used by the injector to determine which services need to be injected into the function when the
3611  * function is invoked. There are three ways in which the function can be annotated with the needed
3612  * dependencies.
3613  *
3614  * # Argument names
3615  *
3616  * The simplest form is to extract the dependencies from the arguments of the function. This is done
3617  * by converting the function into a string using `toString()` method and extracting the argument
3618  * names.
3619  * ```js
3620  *   // Given
3621  *   function MyController($scope, $route) {
3622  *     // ...
3623  *   }
3624  *
3625  *   // Then
3626  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3627  * ```
3628  *
3629  * You can disallow this method by using strict injection mode.
3630  *
3631  * This method does not work with code minification / obfuscation. For this reason the following
3632  * annotation strategies are supported.
3633  *
3634  * # The `$inject` property
3635  *
3636  * If a function has an `$inject` property and its value is an array of strings, then the strings
3637  * represent names of services to be injected into the function.
3638  * ```js
3639  *   // Given
3640  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3641  *     // ...
3642  *   }
3643  *   // Define function dependencies
3644  *   MyController['$inject'] = ['$scope', '$route'];
3645  *
3646  *   // Then
3647  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3648  * ```
3649  *
3650  * # The array notation
3651  *
3652  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3653  * is very inconvenient. In these situations using the array notation to specify the dependencies in
3654  * a way that survives minification is a better choice:
3655  *
3656  * ```js
3657  *   // We wish to write this (not minification / obfuscation safe)
3658  *   injector.invoke(function($compile, $rootScope) {
3659  *     // ...
3660  *   });
3661  *
3662  *   // We are forced to write break inlining
3663  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3664  *     // ...
3665  *   };
3666  *   tmpFn.$inject = ['$compile', '$rootScope'];
3667  *   injector.invoke(tmpFn);
3668  *
3669  *   // To better support inline function the inline annotation is supported
3670  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3671  *     // ...
3672  *   }]);
3673  *
3674  *   // Therefore
3675  *   expect(injector.annotate(
3676  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3677  *    ).toEqual(['$compile', '$rootScope']);
3678  * ```
3679  *
3680  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3681  * be retrieved as described above.
3682  *
3683  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3684  *
3685  * @returns {Array.<string>} The names of the services which the function requires.
3686  */
3687
3688
3689
3690
3691 /**
3692  * @ngdoc service
3693  * @name $provide
3694  *
3695  * @description
3696  *
3697  * The {@link auto.$provide $provide} service has a number of methods for registering components
3698  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3699  * {@link angular.Module}.
3700  *
3701  * An Angular **service** is a singleton object created by a **service factory**.  These **service
3702  * factories** are functions which, in turn, are created by a **service provider**.
3703  * The **service providers** are constructor functions. When instantiated they must contain a
3704  * property called `$get`, which holds the **service factory** function.
3705  *
3706  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3707  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3708  * function to get the instance of the **service**.
3709  *
3710  * Often services have no configuration options and there is no need to add methods to the service
3711  * provider.  The provider will be no more than a constructor function with a `$get` property. For
3712  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3713  * services without specifying a provider.
3714  *
3715  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3716  *     {@link auto.$injector $injector}
3717  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3718  *     providers and services.
3719  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3720  *     services, not providers.
3721  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3722  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3723  *     given factory function.
3724  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3725  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3726  *      a new object using the given constructor function.
3727  *
3728  * See the individual methods for more information and examples.
3729  */
3730
3731 /**
3732  * @ngdoc method
3733  * @name $provide#provider
3734  * @description
3735  *
3736  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3737  * are constructor functions, whose instances are responsible for "providing" a factory for a
3738  * service.
3739  *
3740  * Service provider names start with the name of the service they provide followed by `Provider`.
3741  * For example, the {@link ng.$log $log} service has a provider called
3742  * {@link ng.$logProvider $logProvider}.
3743  *
3744  * Service provider objects can have additional methods which allow configuration of the provider
3745  * and its service. Importantly, you can configure what kind of service is created by the `$get`
3746  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3747  * method {@link ng.$logProvider#debugEnabled debugEnabled}
3748  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3749  * console or not.
3750  *
3751  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3752                         'Provider'` key.
3753  * @param {(Object|function())} provider If the provider is:
3754  *
3755  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3756  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3757  *   - `Constructor`: a new instance of the provider will be created using
3758  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3759  *
3760  * @returns {Object} registered provider instance
3761
3762  * @example
3763  *
3764  * The following example shows how to create a simple event tracking service and register it using
3765  * {@link auto.$provide#provider $provide.provider()}.
3766  *
3767  * ```js
3768  *  // Define the eventTracker provider
3769  *  function EventTrackerProvider() {
3770  *    var trackingUrl = '/track';
3771  *
3772  *    // A provider method for configuring where the tracked events should been saved
3773  *    this.setTrackingUrl = function(url) {
3774  *      trackingUrl = url;
3775  *    };
3776  *
3777  *    // The service factory function
3778  *    this.$get = ['$http', function($http) {
3779  *      var trackedEvents = {};
3780  *      return {
3781  *        // Call this to track an event
3782  *        event: function(event) {
3783  *          var count = trackedEvents[event] || 0;
3784  *          count += 1;
3785  *          trackedEvents[event] = count;
3786  *          return count;
3787  *        },
3788  *        // Call this to save the tracked events to the trackingUrl
3789  *        save: function() {
3790  *          $http.post(trackingUrl, trackedEvents);
3791  *        }
3792  *      };
3793  *    }];
3794  *  }
3795  *
3796  *  describe('eventTracker', function() {
3797  *    var postSpy;
3798  *
3799  *    beforeEach(module(function($provide) {
3800  *      // Register the eventTracker provider
3801  *      $provide.provider('eventTracker', EventTrackerProvider);
3802  *    }));
3803  *
3804  *    beforeEach(module(function(eventTrackerProvider) {
3805  *      // Configure eventTracker provider
3806  *      eventTrackerProvider.setTrackingUrl('/custom-track');
3807  *    }));
3808  *
3809  *    it('tracks events', inject(function(eventTracker) {
3810  *      expect(eventTracker.event('login')).toEqual(1);
3811  *      expect(eventTracker.event('login')).toEqual(2);
3812  *    }));
3813  *
3814  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3815  *      postSpy = spyOn($http, 'post');
3816  *      eventTracker.event('login');
3817  *      eventTracker.save();
3818  *      expect(postSpy).toHaveBeenCalled();
3819  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3820  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3821  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3822  *    }));
3823  *  });
3824  * ```
3825  */
3826
3827 /**
3828  * @ngdoc method
3829  * @name $provide#factory
3830  * @description
3831  *
3832  * Register a **service factory**, which will be called to return the service instance.
3833  * This is short for registering a service where its provider consists of only a `$get` property,
3834  * which is the given service factory function.
3835  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3836  * configure your service in a provider.
3837  *
3838  * @param {string} name The name of the instance.
3839  * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3840  *                            for `$provide.provider(name, {$get: $getFn})`.
3841  * @returns {Object} registered provider instance
3842  *
3843  * @example
3844  * Here is an example of registering a service
3845  * ```js
3846  *   $provide.factory('ping', ['$http', function($http) {
3847  *     return function ping() {
3848  *       return $http.send('/ping');
3849  *     };
3850  *   }]);
3851  * ```
3852  * You would then inject and use this service like this:
3853  * ```js
3854  *   someModule.controller('Ctrl', ['ping', function(ping) {
3855  *     ping();
3856  *   }]);
3857  * ```
3858  */
3859
3860
3861 /**
3862  * @ngdoc method
3863  * @name $provide#service
3864  * @description
3865  *
3866  * Register a **service constructor**, which will be invoked with `new` to create the service
3867  * instance.
3868  * This is short for registering a service where its provider's `$get` property is the service
3869  * constructor function that will be used to instantiate the service instance.
3870  *
3871  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3872  * as a type/class.
3873  *
3874  * @param {string} name The name of the instance.
3875  * @param {Function} constructor A class (constructor function) that will be instantiated.
3876  * @returns {Object} registered provider instance
3877  *
3878  * @example
3879  * Here is an example of registering a service using
3880  * {@link auto.$provide#service $provide.service(class)}.
3881  * ```js
3882  *   var Ping = function($http) {
3883  *     this.$http = $http;
3884  *   };
3885  *
3886  *   Ping.$inject = ['$http'];
3887  *
3888  *   Ping.prototype.send = function() {
3889  *     return this.$http.get('/ping');
3890  *   };
3891  *   $provide.service('ping', Ping);
3892  * ```
3893  * You would then inject and use this service like this:
3894  * ```js
3895  *   someModule.controller('Ctrl', ['ping', function(ping) {
3896  *     ping.send();
3897  *   }]);
3898  * ```
3899  */
3900
3901
3902 /**
3903  * @ngdoc method
3904  * @name $provide#value
3905  * @description
3906  *
3907  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3908  * number, an array, an object or a function.  This is short for registering a service where its
3909  * provider's `$get` property is a factory function that takes no arguments and returns the **value
3910  * service**.
3911  *
3912  * Value services are similar to constant services, except that they cannot be injected into a
3913  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3914  * an Angular
3915  * {@link auto.$provide#decorator decorator}.
3916  *
3917  * @param {string} name The name of the instance.
3918  * @param {*} value The value.
3919  * @returns {Object} registered provider instance
3920  *
3921  * @example
3922  * Here are some examples of creating value services.
3923  * ```js
3924  *   $provide.value('ADMIN_USER', 'admin');
3925  *
3926  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3927  *
3928  *   $provide.value('halfOf', function(value) {
3929  *     return value / 2;
3930  *   });
3931  * ```
3932  */
3933
3934
3935 /**
3936  * @ngdoc method
3937  * @name $provide#constant
3938  * @description
3939  *
3940  * Register a **constant service**, such as a string, a number, an array, an object or a function,
3941  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3942  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3943  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3944  *
3945  * @param {string} name The name of the constant.
3946  * @param {*} value The constant value.
3947  * @returns {Object} registered instance
3948  *
3949  * @example
3950  * Here a some examples of creating constants:
3951  * ```js
3952  *   $provide.constant('SHARD_HEIGHT', 306);
3953  *
3954  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3955  *
3956  *   $provide.constant('double', function(value) {
3957  *     return value * 2;
3958  *   });
3959  * ```
3960  */
3961
3962
3963 /**
3964  * @ngdoc method
3965  * @name $provide#decorator
3966  * @description
3967  *
3968  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3969  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3970  * service. The object returned by the decorator may be the original service, or a new service
3971  * object which replaces or wraps and delegates to the original service.
3972  *
3973  * @param {string} name The name of the service to decorate.
3974  * @param {function()} decorator This function will be invoked when the service needs to be
3975  *    instantiated and should return the decorated service instance. The function is called using
3976  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3977  *    Local injection arguments:
3978  *
3979  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3980  *      decorated or delegated to.
3981  *
3982  * @example
3983  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3984  * calls to {@link ng.$log#error $log.warn()}.
3985  * ```js
3986  *   $provide.decorator('$log', ['$delegate', function($delegate) {
3987  *     $delegate.warn = $delegate.error;
3988  *     return $delegate;
3989  *   }]);
3990  * ```
3991  */
3992
3993
3994 function createInjector(modulesToLoad, strictDi) {
3995   strictDi = (strictDi === true);
3996   var INSTANTIATING = {},
3997       providerSuffix = 'Provider',
3998       path = [],
3999       loadedModules = new HashMap([], true),
4000       providerCache = {
4001         $provide: {
4002             provider: supportObject(provider),
4003             factory: supportObject(factory),
4004             service: supportObject(service),
4005             value: supportObject(value),
4006             constant: supportObject(constant),
4007             decorator: decorator
4008           }
4009       },
4010       providerInjector = (providerCache.$injector =
4011           createInternalInjector(providerCache, function(serviceName, caller) {
4012             if (angular.isString(caller)) {
4013               path.push(caller);
4014             }
4015             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4016           })),
4017       instanceCache = {},
4018       instanceInjector = (instanceCache.$injector =
4019           createInternalInjector(instanceCache, function(serviceName, caller) {
4020             var provider = providerInjector.get(serviceName + providerSuffix, caller);
4021             return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4022           }));
4023
4024
4025   forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
4026
4027   return instanceInjector;
4028
4029   ////////////////////////////////////
4030   // $provider
4031   ////////////////////////////////////
4032
4033   function supportObject(delegate) {
4034     return function(key, value) {
4035       if (isObject(key)) {
4036         forEach(key, reverseParams(delegate));
4037       } else {
4038         return delegate(key, value);
4039       }
4040     };
4041   }
4042
4043   function provider(name, provider_) {
4044     assertNotHasOwnProperty(name, 'service');
4045     if (isFunction(provider_) || isArray(provider_)) {
4046       provider_ = providerInjector.instantiate(provider_);
4047     }
4048     if (!provider_.$get) {
4049       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4050     }
4051     return providerCache[name + providerSuffix] = provider_;
4052   }
4053
4054   function enforceReturnValue(name, factory) {
4055     return function enforcedReturnValue() {
4056       var result = instanceInjector.invoke(factory, this);
4057       if (isUndefined(result)) {
4058         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4059       }
4060       return result;
4061     };
4062   }
4063
4064   function factory(name, factoryFn, enforce) {
4065     return provider(name, {
4066       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4067     });
4068   }
4069
4070   function service(name, constructor) {
4071     return factory(name, ['$injector', function($injector) {
4072       return $injector.instantiate(constructor);
4073     }]);
4074   }
4075
4076   function value(name, val) { return factory(name, valueFn(val), false); }
4077
4078   function constant(name, value) {
4079     assertNotHasOwnProperty(name, 'constant');
4080     providerCache[name] = value;
4081     instanceCache[name] = value;
4082   }
4083
4084   function decorator(serviceName, decorFn) {
4085     var origProvider = providerInjector.get(serviceName + providerSuffix),
4086         orig$get = origProvider.$get;
4087
4088     origProvider.$get = function() {
4089       var origInstance = instanceInjector.invoke(orig$get, origProvider);
4090       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4091     };
4092   }
4093
4094   ////////////////////////////////////
4095   // Module Loading
4096   ////////////////////////////////////
4097   function loadModules(modulesToLoad) {
4098     var runBlocks = [], moduleFn;
4099     forEach(modulesToLoad, function(module) {
4100       if (loadedModules.get(module)) return;
4101       loadedModules.put(module, true);
4102
4103       function runInvokeQueue(queue) {
4104         var i, ii;
4105         for (i = 0, ii = queue.length; i < ii; i++) {
4106           var invokeArgs = queue[i],
4107               provider = providerInjector.get(invokeArgs[0]);
4108
4109           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4110         }
4111       }
4112
4113       try {
4114         if (isString(module)) {
4115           moduleFn = angularModule(module);
4116           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4117           runInvokeQueue(moduleFn._invokeQueue);
4118           runInvokeQueue(moduleFn._configBlocks);
4119         } else if (isFunction(module)) {
4120             runBlocks.push(providerInjector.invoke(module));
4121         } else if (isArray(module)) {
4122             runBlocks.push(providerInjector.invoke(module));
4123         } else {
4124           assertArgFn(module, 'module');
4125         }
4126       } catch (e) {
4127         if (isArray(module)) {
4128           module = module[module.length - 1];
4129         }
4130         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4131           // Safari & FF's stack traces don't contain error.message content
4132           // unlike those of Chrome and IE
4133           // So if stack doesn't contain message, we create a new string that contains both.
4134           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4135           /* jshint -W022 */
4136           e = e.message + '\n' + e.stack;
4137         }
4138         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4139                   module, e.stack || e.message || e);
4140       }
4141     });
4142     return runBlocks;
4143   }
4144
4145   ////////////////////////////////////
4146   // internal Injector
4147   ////////////////////////////////////
4148
4149   function createInternalInjector(cache, factory) {
4150
4151     function getService(serviceName, caller) {
4152       if (cache.hasOwnProperty(serviceName)) {
4153         if (cache[serviceName] === INSTANTIATING) {
4154           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4155                     serviceName + ' <- ' + path.join(' <- '));
4156         }
4157         return cache[serviceName];
4158       } else {
4159         try {
4160           path.unshift(serviceName);
4161           cache[serviceName] = INSTANTIATING;
4162           return cache[serviceName] = factory(serviceName, caller);
4163         } catch (err) {
4164           if (cache[serviceName] === INSTANTIATING) {
4165             delete cache[serviceName];
4166           }
4167           throw err;
4168         } finally {
4169           path.shift();
4170         }
4171       }
4172     }
4173
4174     function invoke(fn, self, locals, serviceName) {
4175       if (typeof locals === 'string') {
4176         serviceName = locals;
4177         locals = null;
4178       }
4179
4180       var args = [],
4181           $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4182           length, i,
4183           key;
4184
4185       for (i = 0, length = $inject.length; i < length; i++) {
4186         key = $inject[i];
4187         if (typeof key !== 'string') {
4188           throw $injectorMinErr('itkn',
4189                   'Incorrect injection token! Expected service name as string, got {0}', key);
4190         }
4191         args.push(
4192           locals && locals.hasOwnProperty(key)
4193           ? locals[key]
4194           : getService(key, serviceName)
4195         );
4196       }
4197       if (isArray(fn)) {
4198         fn = fn[length];
4199       }
4200
4201       // http://jsperf.com/angularjs-invoke-apply-vs-switch
4202       // #5388
4203       return fn.apply(self, args);
4204     }
4205
4206     function instantiate(Type, locals, serviceName) {
4207       // Check if Type is annotated and use just the given function at n-1 as parameter
4208       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4209       // Object creation: http://jsperf.com/create-constructor/2
4210       var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4211       var returnedValue = invoke(Type, instance, locals, serviceName);
4212
4213       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4214     }
4215
4216     return {
4217       invoke: invoke,
4218       instantiate: instantiate,
4219       get: getService,
4220       annotate: createInjector.$$annotate,
4221       has: function(name) {
4222         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4223       }
4224     };
4225   }
4226 }
4227
4228 createInjector.$$annotate = annotate;
4229
4230 /**
4231  * @ngdoc provider
4232  * @name $anchorScrollProvider
4233  *
4234  * @description
4235  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4236  * {@link ng.$location#hash $location.hash()} changes.
4237  */
4238 function $AnchorScrollProvider() {
4239
4240   var autoScrollingEnabled = true;
4241
4242   /**
4243    * @ngdoc method
4244    * @name $anchorScrollProvider#disableAutoScrolling
4245    *
4246    * @description
4247    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4248    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4249    * Use this method to disable automatic scrolling.
4250    *
4251    * If automatic scrolling is disabled, one must explicitly call
4252    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4253    * current hash.
4254    */
4255   this.disableAutoScrolling = function() {
4256     autoScrollingEnabled = false;
4257   };
4258
4259   /**
4260    * @ngdoc service
4261    * @name $anchorScroll
4262    * @kind function
4263    * @requires $window
4264    * @requires $location
4265    * @requires $rootScope
4266    *
4267    * @description
4268    * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
4269    * scrolls to the related element, according to the rules specified in the
4270    * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4271    *
4272    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4273    * match any anchor whenever it changes. This can be disabled by calling
4274    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4275    *
4276    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4277    * vertical scroll-offset (either fixed or dynamic).
4278    *
4279    * @property {(number|function|jqLite)} yOffset
4280    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4281    * positioned elements at the top of the page, such as navbars, headers etc.
4282    *
4283    * `yOffset` can be specified in various ways:
4284    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4285    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4286    *   a number representing the offset (in pixels).<br /><br />
4287    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4288    *   the top of the page to the element's bottom will be used as offset.<br />
4289    *   **Note**: The element will be taken into account only as long as its `position` is set to
4290    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4291    *   their height and/or positioning according to the viewport's size.
4292    *
4293    * <br />
4294    * <div class="alert alert-warning">
4295    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4296    * not some child element.
4297    * </div>
4298    *
4299    * @example
4300      <example module="anchorScrollExample">
4301        <file name="index.html">
4302          <div id="scrollArea" ng-controller="ScrollController">
4303            <a ng-click="gotoBottom()">Go to bottom</a>
4304            <a id="bottom"></a> You're at the bottom!
4305          </div>
4306        </file>
4307        <file name="script.js">
4308          angular.module('anchorScrollExample', [])
4309            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4310              function ($scope, $location, $anchorScroll) {
4311                $scope.gotoBottom = function() {
4312                  // set the location.hash to the id of
4313                  // the element you wish to scroll to.
4314                  $location.hash('bottom');
4315
4316                  // call $anchorScroll()
4317                  $anchorScroll();
4318                };
4319              }]);
4320        </file>
4321        <file name="style.css">
4322          #scrollArea {
4323            height: 280px;
4324            overflow: auto;
4325          }
4326
4327          #bottom {
4328            display: block;
4329            margin-top: 2000px;
4330          }
4331        </file>
4332      </example>
4333    *
4334    * <hr />
4335    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4336    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4337    *
4338    * @example
4339      <example module="anchorScrollOffsetExample">
4340        <file name="index.html">
4341          <div class="fixed-header" ng-controller="headerCtrl">
4342            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4343              Go to anchor {{x}}
4344            </a>
4345          </div>
4346          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4347            Anchor {{x}} of 5
4348          </div>
4349        </file>
4350        <file name="script.js">
4351          angular.module('anchorScrollOffsetExample', [])
4352            .run(['$anchorScroll', function($anchorScroll) {
4353              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4354            }])
4355            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4356              function ($anchorScroll, $location, $scope) {
4357                $scope.gotoAnchor = function(x) {
4358                  var newHash = 'anchor' + x;
4359                  if ($location.hash() !== newHash) {
4360                    // set the $location.hash to `newHash` and
4361                    // $anchorScroll will automatically scroll to it
4362                    $location.hash('anchor' + x);
4363                  } else {
4364                    // call $anchorScroll() explicitly,
4365                    // since $location.hash hasn't changed
4366                    $anchorScroll();
4367                  }
4368                };
4369              }
4370            ]);
4371        </file>
4372        <file name="style.css">
4373          body {
4374            padding-top: 50px;
4375          }
4376
4377          .anchor {
4378            border: 2px dashed DarkOrchid;
4379            padding: 10px 10px 200px 10px;
4380          }
4381
4382          .fixed-header {
4383            background-color: rgba(0, 0, 0, 0.2);
4384            height: 50px;
4385            position: fixed;
4386            top: 0; left: 0; right: 0;
4387          }
4388
4389          .fixed-header > a {
4390            display: inline-block;
4391            margin: 5px 15px;
4392          }
4393        </file>
4394      </example>
4395    */
4396   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4397     var document = $window.document;
4398
4399     // Helper function to get first anchor from a NodeList
4400     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4401     //  and working in all supported browsers.)
4402     function getFirstAnchor(list) {
4403       var result = null;
4404       Array.prototype.some.call(list, function(element) {
4405         if (nodeName_(element) === 'a') {
4406           result = element;
4407           return true;
4408         }
4409       });
4410       return result;
4411     }
4412
4413     function getYOffset() {
4414
4415       var offset = scroll.yOffset;
4416
4417       if (isFunction(offset)) {
4418         offset = offset();
4419       } else if (isElement(offset)) {
4420         var elem = offset[0];
4421         var style = $window.getComputedStyle(elem);
4422         if (style.position !== 'fixed') {
4423           offset = 0;
4424         } else {
4425           offset = elem.getBoundingClientRect().bottom;
4426         }
4427       } else if (!isNumber(offset)) {
4428         offset = 0;
4429       }
4430
4431       return offset;
4432     }
4433
4434     function scrollTo(elem) {
4435       if (elem) {
4436         elem.scrollIntoView();
4437
4438         var offset = getYOffset();
4439
4440         if (offset) {
4441           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4442           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4443           // top of the viewport.
4444           //
4445           // IF the number of pixels from the top of `elem` to the end of the page's content is less
4446           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4447           // way down the page.
4448           //
4449           // This is often the case for elements near the bottom of the page.
4450           //
4451           // In such cases we do not need to scroll the whole `offset` up, just the difference between
4452           // the top of the element and the offset, which is enough to align the top of `elem` at the
4453           // desired position.
4454           var elemTop = elem.getBoundingClientRect().top;
4455           $window.scrollBy(0, elemTop - offset);
4456         }
4457       } else {
4458         $window.scrollTo(0, 0);
4459       }
4460     }
4461
4462     function scroll() {
4463       var hash = $location.hash(), elm;
4464
4465       // empty hash, scroll to the top of the page
4466       if (!hash) scrollTo(null);
4467
4468       // element with given id
4469       else if ((elm = document.getElementById(hash))) scrollTo(elm);
4470
4471       // first anchor with given name :-D
4472       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4473
4474       // no element and hash == 'top', scroll to the top of the page
4475       else if (hash === 'top') scrollTo(null);
4476     }
4477
4478     // does not scroll when user clicks on anchor link that is currently on
4479     // (no url change, no $location.hash() change), browser native does scroll
4480     if (autoScrollingEnabled) {
4481       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4482         function autoScrollWatchAction(newVal, oldVal) {
4483           // skip the initial scroll if $location.hash is empty
4484           if (newVal === oldVal && newVal === '') return;
4485
4486           jqLiteDocumentLoaded(function() {
4487             $rootScope.$evalAsync(scroll);
4488           });
4489         });
4490     }
4491
4492     return scroll;
4493   }];
4494 }
4495
4496 var $animateMinErr = minErr('$animate');
4497
4498 /**
4499  * @ngdoc provider
4500  * @name $animateProvider
4501  *
4502  * @description
4503  * Default implementation of $animate that doesn't perform any animations, instead just
4504  * synchronously performs DOM
4505  * updates and calls done() callbacks.
4506  *
4507  * In order to enable animations the ngAnimate module has to be loaded.
4508  *
4509  * To see the functional implementation check out src/ngAnimate/animate.js
4510  */
4511 var $AnimateProvider = ['$provide', function($provide) {
4512
4513
4514   this.$$selectors = {};
4515
4516
4517   /**
4518    * @ngdoc method
4519    * @name $animateProvider#register
4520    *
4521    * @description
4522    * Registers a new injectable animation factory function. The factory function produces the
4523    * animation object which contains callback functions for each event that is expected to be
4524    * animated.
4525    *
4526    *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4527    *   must be called once the element animation is complete. If a function is returned then the
4528    *   animation service will use this function to cancel the animation whenever a cancel event is
4529    *   triggered.
4530    *
4531    *
4532    * ```js
4533    *   return {
4534      *     eventFn : function(element, done) {
4535      *       //code to run the animation
4536      *       //once complete, then run done()
4537      *       return function cancellationFunction() {
4538      *         //code to cancel the animation
4539      *       }
4540      *     }
4541      *   }
4542    * ```
4543    *
4544    * @param {string} name The name of the animation.
4545    * @param {Function} factory The factory function that will be executed to return the animation
4546    *                           object.
4547    */
4548   this.register = function(name, factory) {
4549     var key = name + '-animation';
4550     if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4551         "Expecting class selector starting with '.' got '{0}'.", name);
4552     this.$$selectors[name.substr(1)] = key;
4553     $provide.factory(key, factory);
4554   };
4555
4556   /**
4557    * @ngdoc method
4558    * @name $animateProvider#classNameFilter
4559    *
4560    * @description
4561    * Sets and/or returns the CSS class regular expression that is checked when performing
4562    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4563    * therefore enable $animate to attempt to perform an animation on any element.
4564    * When setting the classNameFilter value, animations will only be performed on elements
4565    * that successfully match the filter expression. This in turn can boost performance
4566    * for low-powered devices as well as applications containing a lot of structural operations.
4567    * @param {RegExp=} expression The className expression which will be checked against all animations
4568    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4569    */
4570   this.classNameFilter = function(expression) {
4571     if (arguments.length === 1) {
4572       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4573     }
4574     return this.$$classNameFilter;
4575   };
4576
4577   this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) {
4578
4579     var currentDefer;
4580
4581     function runAnimationPostDigest(fn) {
4582       var cancelFn, defer = $$q.defer();
4583       defer.promise.$$cancelFn = function ngAnimateMaybeCancel() {
4584         cancelFn && cancelFn();
4585       };
4586
4587       $rootScope.$$postDigest(function ngAnimatePostDigest() {
4588         cancelFn = fn(function ngAnimateNotifyComplete() {
4589           defer.resolve();
4590         });
4591       });
4592
4593       return defer.promise;
4594     }
4595
4596     function resolveElementClasses(element, classes) {
4597       var toAdd = [], toRemove = [];
4598
4599       var hasClasses = createMap();
4600       forEach((element.attr('class') || '').split(/\s+/), function(className) {
4601         hasClasses[className] = true;
4602       });
4603
4604       forEach(classes, function(status, className) {
4605         var hasClass = hasClasses[className];
4606
4607         // If the most recent class manipulation (via $animate) was to remove the class, and the
4608         // element currently has the class, the class is scheduled for removal. Otherwise, if
4609         // the most recent class manipulation (via $animate) was to add the class, and the
4610         // element does not currently have the class, the class is scheduled to be added.
4611         if (status === false && hasClass) {
4612           toRemove.push(className);
4613         } else if (status === true && !hasClass) {
4614           toAdd.push(className);
4615         }
4616       });
4617
4618       return (toAdd.length + toRemove.length) > 0 &&
4619         [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
4620     }
4621
4622     function cachedClassManipulation(cache, classes, op) {
4623       for (var i=0, ii = classes.length; i < ii; ++i) {
4624         var className = classes[i];
4625         cache[className] = op;
4626       }
4627     }
4628
4629     function asyncPromise() {
4630       // only serve one instance of a promise in order to save CPU cycles
4631       if (!currentDefer) {
4632         currentDefer = $$q.defer();
4633         $$asyncCallback(function() {
4634           currentDefer.resolve();
4635           currentDefer = null;
4636         });
4637       }
4638       return currentDefer.promise;
4639     }
4640
4641     function applyStyles(element, options) {
4642       if (angular.isObject(options)) {
4643         var styles = extend(options.from || {}, options.to || {});
4644         element.css(styles);
4645       }
4646     }
4647
4648     /**
4649      *
4650      * @ngdoc service
4651      * @name $animate
4652      * @description The $animate service provides rudimentary DOM manipulation functions to
4653      * insert, remove and move elements within the DOM, as well as adding and removing classes.
4654      * This service is the core service used by the ngAnimate $animator service which provides
4655      * high-level animation hooks for CSS and JavaScript.
4656      *
4657      * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4658      * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4659      * manipulation operations.
4660      *
4661      * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4662      * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4663      * page}.
4664      */
4665     return {
4666       animate: function(element, from, to) {
4667         applyStyles(element, { from: from, to: to });
4668         return asyncPromise();
4669       },
4670
4671       /**
4672        *
4673        * @ngdoc method
4674        * @name $animate#enter
4675        * @kind function
4676        * @description Inserts the element into the DOM either after the `after` element or
4677        * as the first child within the `parent` element. When the function is called a promise
4678        * is returned that will be resolved at a later time.
4679        * @param {DOMElement} element the element which will be inserted into the DOM
4680        * @param {DOMElement} parent the parent element which will append the element as
4681        *   a child (if the after element is not present)
4682        * @param {DOMElement} after the sibling element which will append the element
4683        *   after itself
4684        * @param {object=} options an optional collection of styles that will be applied to the element.
4685        * @return {Promise} the animation callback promise
4686        */
4687       enter: function(element, parent, after, options) {
4688         applyStyles(element, options);
4689         after ? after.after(element)
4690               : parent.prepend(element);
4691         return asyncPromise();
4692       },
4693
4694       /**
4695        *
4696        * @ngdoc method
4697        * @name $animate#leave
4698        * @kind function
4699        * @description Removes the element from the DOM. When the function is called a promise
4700        * is returned that will be resolved at a later time.
4701        * @param {DOMElement} element the element which will be removed from the DOM
4702        * @param {object=} options an optional collection of options that will be applied to the element.
4703        * @return {Promise} the animation callback promise
4704        */
4705       leave: function(element, options) {
4706         applyStyles(element, options);
4707         element.remove();
4708         return asyncPromise();
4709       },
4710
4711       /**
4712        *
4713        * @ngdoc method
4714        * @name $animate#move
4715        * @kind function
4716        * @description Moves the position of the provided element within the DOM to be placed
4717        * either after the `after` element or inside of the `parent` element. When the function
4718        * is called a promise is returned that will be resolved at a later time.
4719        *
4720        * @param {DOMElement} element the element which will be moved around within the
4721        *   DOM
4722        * @param {DOMElement} parent the parent element where the element will be
4723        *   inserted into (if the after element is not present)
4724        * @param {DOMElement} after the sibling element where the element will be
4725        *   positioned next to
4726        * @param {object=} options an optional collection of options that will be applied to the element.
4727        * @return {Promise} the animation callback promise
4728        */
4729       move: function(element, parent, after, options) {
4730         // Do not remove element before insert. Removing will cause data associated with the
4731         // element to be dropped. Insert will implicitly do the remove.
4732         return this.enter(element, parent, after, options);
4733       },
4734
4735       /**
4736        *
4737        * @ngdoc method
4738        * @name $animate#addClass
4739        * @kind function
4740        * @description Adds the provided className CSS class value to the provided element.
4741        * When the function is called a promise is returned that will be resolved at a later time.
4742        * @param {DOMElement} element the element which will have the className value
4743        *   added to it
4744        * @param {string} className the CSS class which will be added to the element
4745        * @param {object=} options an optional collection of options that will be applied to the element.
4746        * @return {Promise} the animation callback promise
4747        */
4748       addClass: function(element, className, options) {
4749         return this.setClass(element, className, [], options);
4750       },
4751
4752       $$addClassImmediately: function(element, className, options) {
4753         element = jqLite(element);
4754         className = !isString(className)
4755                         ? (isArray(className) ? className.join(' ') : '')
4756                         : className;
4757         forEach(element, function(element) {
4758           jqLiteAddClass(element, className);
4759         });
4760         applyStyles(element, options);
4761         return asyncPromise();
4762       },
4763
4764       /**
4765        *
4766        * @ngdoc method
4767        * @name $animate#removeClass
4768        * @kind function
4769        * @description Removes the provided className CSS class value from the provided element.
4770        * When the function is called a promise is returned that will be resolved at a later time.
4771        * @param {DOMElement} element the element which will have the className value
4772        *   removed from it
4773        * @param {string} className the CSS class which will be removed from the element
4774        * @param {object=} options an optional collection of options that will be applied to the element.
4775        * @return {Promise} the animation callback promise
4776        */
4777       removeClass: function(element, className, options) {
4778         return this.setClass(element, [], className, options);
4779       },
4780
4781       $$removeClassImmediately: function(element, className, options) {
4782         element = jqLite(element);
4783         className = !isString(className)
4784                         ? (isArray(className) ? className.join(' ') : '')
4785                         : className;
4786         forEach(element, function(element) {
4787           jqLiteRemoveClass(element, className);
4788         });
4789         applyStyles(element, options);
4790         return asyncPromise();
4791       },
4792
4793       /**
4794        *
4795        * @ngdoc method
4796        * @name $animate#setClass
4797        * @kind function
4798        * @description Adds and/or removes the given CSS classes to and from the element.
4799        * When the function is called a promise is returned that will be resolved at a later time.
4800        * @param {DOMElement} element the element which will have its CSS classes changed
4801        *   removed from it
4802        * @param {string} add the CSS classes which will be added to the element
4803        * @param {string} remove the CSS class which will be removed from the element
4804        * @param {object=} options an optional collection of options that will be applied to the element.
4805        * @return {Promise} the animation callback promise
4806        */
4807       setClass: function(element, add, remove, options) {
4808         var self = this;
4809         var STORAGE_KEY = '$$animateClasses';
4810         var createdCache = false;
4811         element = jqLite(element);
4812
4813         var cache = element.data(STORAGE_KEY);
4814         if (!cache) {
4815           cache = {
4816             classes: {},
4817             options: options
4818           };
4819           createdCache = true;
4820         } else if (options && cache.options) {
4821           cache.options = angular.extend(cache.options || {}, options);
4822         }
4823
4824         var classes = cache.classes;
4825
4826         add = isArray(add) ? add : add.split(' ');
4827         remove = isArray(remove) ? remove : remove.split(' ');
4828         cachedClassManipulation(classes, add, true);
4829         cachedClassManipulation(classes, remove, false);
4830
4831         if (createdCache) {
4832           cache.promise = runAnimationPostDigest(function(done) {
4833             var cache = element.data(STORAGE_KEY);
4834             element.removeData(STORAGE_KEY);
4835
4836             // in the event that the element is removed before postDigest
4837             // is run then the cache will be undefined and there will be
4838             // no need anymore to add or remove and of the element classes
4839             if (cache) {
4840               var classes = resolveElementClasses(element, cache.classes);
4841               if (classes) {
4842                 self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
4843               }
4844             }
4845
4846             done();
4847           });
4848           element.data(STORAGE_KEY, cache);
4849         }
4850
4851         return cache.promise;
4852       },
4853
4854       $$setClassImmediately: function(element, add, remove, options) {
4855         add && this.$$addClassImmediately(element, add);
4856         remove && this.$$removeClassImmediately(element, remove);
4857         applyStyles(element, options);
4858         return asyncPromise();
4859       },
4860
4861       enabled: noop,
4862       cancel: noop
4863     };
4864   }];
4865 }];
4866
4867 function $$AsyncCallbackProvider() {
4868   this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4869     return $$rAF.supported
4870       ? function(fn) { return $$rAF(fn); }
4871       : function(fn) {
4872         return $timeout(fn, 0, false);
4873       };
4874   }];
4875 }
4876
4877 /* global stripHash: true */
4878
4879 /**
4880  * ! This is a private undocumented service !
4881  *
4882  * @name $browser
4883  * @requires $log
4884  * @description
4885  * This object has two goals:
4886  *
4887  * - hide all the global state in the browser caused by the window object
4888  * - abstract away all the browser specific features and inconsistencies
4889  *
4890  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4891  * service, which can be used for convenient testing of the application without the interaction with
4892  * the real browser apis.
4893  */
4894 /**
4895  * @param {object} window The global window object.
4896  * @param {object} document jQuery wrapped document.
4897  * @param {object} $log window.console or an object with the same interface.
4898  * @param {object} $sniffer $sniffer service
4899  */
4900 function Browser(window, document, $log, $sniffer) {
4901   var self = this,
4902       rawDocument = document[0],
4903       location = window.location,
4904       history = window.history,
4905       setTimeout = window.setTimeout,
4906       clearTimeout = window.clearTimeout,
4907       pendingDeferIds = {};
4908
4909   self.isMock = false;
4910
4911   var outstandingRequestCount = 0;
4912   var outstandingRequestCallbacks = [];
4913
4914   // TODO(vojta): remove this temporary api
4915   self.$$completeOutstandingRequest = completeOutstandingRequest;
4916   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4917
4918   /**
4919    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4920    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4921    */
4922   function completeOutstandingRequest(fn) {
4923     try {
4924       fn.apply(null, sliceArgs(arguments, 1));
4925     } finally {
4926       outstandingRequestCount--;
4927       if (outstandingRequestCount === 0) {
4928         while (outstandingRequestCallbacks.length) {
4929           try {
4930             outstandingRequestCallbacks.pop()();
4931           } catch (e) {
4932             $log.error(e);
4933           }
4934         }
4935       }
4936     }
4937   }
4938
4939   function getHash(url) {
4940     var index = url.indexOf('#');
4941     return index === -1 ? '' : url.substr(index + 1);
4942   }
4943
4944   /**
4945    * @private
4946    * Note: this method is used only by scenario runner
4947    * TODO(vojta): prefix this method with $$ ?
4948    * @param {function()} callback Function that will be called when no outstanding request
4949    */
4950   self.notifyWhenNoOutstandingRequests = function(callback) {
4951     // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4952     // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4953     // regular poller would result in flaky tests.
4954     forEach(pollFns, function(pollFn) { pollFn(); });
4955
4956     if (outstandingRequestCount === 0) {
4957       callback();
4958     } else {
4959       outstandingRequestCallbacks.push(callback);
4960     }
4961   };
4962
4963   //////////////////////////////////////////////////////////////
4964   // Poll Watcher API
4965   //////////////////////////////////////////////////////////////
4966   var pollFns = [],
4967       pollTimeout;
4968
4969   /**
4970    * @name $browser#addPollFn
4971    *
4972    * @param {function()} fn Poll function to add
4973    *
4974    * @description
4975    * Adds a function to the list of functions that poller periodically executes,
4976    * and starts polling if not started yet.
4977    *
4978    * @returns {function()} the added function
4979    */
4980   self.addPollFn = function(fn) {
4981     if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4982     pollFns.push(fn);
4983     return fn;
4984   };
4985
4986   /**
4987    * @param {number} interval How often should browser call poll functions (ms)
4988    * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4989    *
4990    * @description
4991    * Configures the poller to run in the specified intervals, using the specified
4992    * setTimeout fn and kicks it off.
4993    */
4994   function startPoller(interval, setTimeout) {
4995     (function check() {
4996       forEach(pollFns, function(pollFn) { pollFn(); });
4997       pollTimeout = setTimeout(check, interval);
4998     })();
4999   }
5000
5001   //////////////////////////////////////////////////////////////
5002   // URL API
5003   //////////////////////////////////////////////////////////////
5004
5005   var cachedState, lastHistoryState,
5006       lastBrowserUrl = location.href,
5007       baseElement = document.find('base'),
5008       reloadLocation = null;
5009
5010   cacheState();
5011   lastHistoryState = cachedState;
5012
5013   /**
5014    * @name $browser#url
5015    *
5016    * @description
5017    * GETTER:
5018    * Without any argument, this method just returns current value of location.href.
5019    *
5020    * SETTER:
5021    * With at least one argument, this method sets url to new value.
5022    * If html5 history api supported, pushState/replaceState is used, otherwise
5023    * location.href/location.replace is used.
5024    * Returns its own instance to allow chaining
5025    *
5026    * NOTE: this api is intended for use only by the $location service. Please use the
5027    * {@link ng.$location $location service} to change url.
5028    *
5029    * @param {string} url New url (when used as setter)
5030    * @param {boolean=} replace Should new url replace current history record?
5031    * @param {object=} state object to use with pushState/replaceState
5032    */
5033   self.url = function(url, replace, state) {
5034     // In modern browsers `history.state` is `null` by default; treating it separately
5035     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5036     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5037     if (isUndefined(state)) {
5038       state = null;
5039     }
5040
5041     // Android Browser BFCache causes location, history reference to become stale.
5042     if (location !== window.location) location = window.location;
5043     if (history !== window.history) history = window.history;
5044
5045     // setter
5046     if (url) {
5047       var sameState = lastHistoryState === state;
5048
5049       // Don't change anything if previous and current URLs and states match. This also prevents
5050       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5051       // See https://github.com/angular/angular.js/commit/ffb2701
5052       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5053         return self;
5054       }
5055       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5056       lastBrowserUrl = url;
5057       lastHistoryState = state;
5058       // Don't use history API if only the hash changed
5059       // due to a bug in IE10/IE11 which leads
5060       // to not firing a `hashchange` nor `popstate` event
5061       // in some cases (see #9143).
5062       if ($sniffer.history && (!sameBase || !sameState)) {
5063         history[replace ? 'replaceState' : 'pushState'](state, '', url);
5064         cacheState();
5065         // Do the assignment again so that those two variables are referentially identical.
5066         lastHistoryState = cachedState;
5067       } else {
5068         if (!sameBase) {
5069           reloadLocation = url;
5070         }
5071         if (replace) {
5072           location.replace(url);
5073         } else if (!sameBase) {
5074           location.href = url;
5075         } else {
5076           location.hash = getHash(url);
5077         }
5078       }
5079       return self;
5080     // getter
5081     } else {
5082       // - reloadLocation is needed as browsers don't allow to read out
5083       //   the new location.href if a reload happened.
5084       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5085       return reloadLocation || location.href.replace(/%27/g,"'");
5086     }
5087   };
5088
5089   /**
5090    * @name $browser#state
5091    *
5092    * @description
5093    * This method is a getter.
5094    *
5095    * Return history.state or null if history.state is undefined.
5096    *
5097    * @returns {object} state
5098    */
5099   self.state = function() {
5100     return cachedState;
5101   };
5102
5103   var urlChangeListeners = [],
5104       urlChangeInit = false;
5105
5106   function cacheStateAndFireUrlChange() {
5107     cacheState();
5108     fireUrlChange();
5109   }
5110
5111   function getCurrentState() {
5112     try {
5113       return history.state;
5114     } catch (e) {
5115       // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5116     }
5117   }
5118
5119   // This variable should be used *only* inside the cacheState function.
5120   var lastCachedState = null;
5121   function cacheState() {
5122     // This should be the only place in $browser where `history.state` is read.
5123     cachedState = getCurrentState();
5124     cachedState = isUndefined(cachedState) ? null : cachedState;
5125
5126     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5127     if (equals(cachedState, lastCachedState)) {
5128       cachedState = lastCachedState;
5129     }
5130     lastCachedState = cachedState;
5131   }
5132
5133   function fireUrlChange() {
5134     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5135       return;
5136     }
5137
5138     lastBrowserUrl = self.url();
5139     lastHistoryState = cachedState;
5140     forEach(urlChangeListeners, function(listener) {
5141       listener(self.url(), cachedState);
5142     });
5143   }
5144
5145   /**
5146    * @name $browser#onUrlChange
5147    *
5148    * @description
5149    * Register callback function that will be called, when url changes.
5150    *
5151    * It's only called when the url is changed from outside of angular:
5152    * - user types different url into address bar
5153    * - user clicks on history (forward/back) button
5154    * - user clicks on a link
5155    *
5156    * It's not called when url is changed by $browser.url() method
5157    *
5158    * The listener gets called with new url as parameter.
5159    *
5160    * NOTE: this api is intended for use only by the $location service. Please use the
5161    * {@link ng.$location $location service} to monitor url changes in angular apps.
5162    *
5163    * @param {function(string)} listener Listener function to be called when url changes.
5164    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5165    */
5166   self.onUrlChange = function(callback) {
5167     // TODO(vojta): refactor to use node's syntax for events
5168     if (!urlChangeInit) {
5169       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5170       // don't fire popstate when user change the address bar and don't fire hashchange when url
5171       // changed by push/replaceState
5172
5173       // html5 history api - popstate event
5174       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5175       // hashchange event
5176       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5177
5178       urlChangeInit = true;
5179     }
5180
5181     urlChangeListeners.push(callback);
5182     return callback;
5183   };
5184
5185   /**
5186    * Checks whether the url has changed outside of Angular.
5187    * Needs to be exported to be able to check for changes that have been done in sync,
5188    * as hashchange/popstate events fire in async.
5189    */
5190   self.$$checkUrlChange = fireUrlChange;
5191
5192   //////////////////////////////////////////////////////////////
5193   // Misc API
5194   //////////////////////////////////////////////////////////////
5195
5196   /**
5197    * @name $browser#baseHref
5198    *
5199    * @description
5200    * Returns current <base href>
5201    * (always relative - without domain)
5202    *
5203    * @returns {string} The current base href
5204    */
5205   self.baseHref = function() {
5206     var href = baseElement.attr('href');
5207     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5208   };
5209
5210   //////////////////////////////////////////////////////////////
5211   // Cookies API
5212   //////////////////////////////////////////////////////////////
5213   var lastCookies = {};
5214   var lastCookieString = '';
5215   var cookiePath = self.baseHref();
5216
5217   function safeDecodeURIComponent(str) {
5218     try {
5219       return decodeURIComponent(str);
5220     } catch (e) {
5221       return str;
5222     }
5223   }
5224
5225   /**
5226    * @name $browser#cookies
5227    *
5228    * @param {string=} name Cookie name
5229    * @param {string=} value Cookie value
5230    *
5231    * @description
5232    * The cookies method provides a 'private' low level access to browser cookies.
5233    * It is not meant to be used directly, use the $cookie service instead.
5234    *
5235    * The return values vary depending on the arguments that the method was called with as follows:
5236    *
5237    * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
5238    *   it
5239    * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
5240    * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
5241    *   way)
5242    *
5243    * @returns {Object} Hash of all cookies (if called without any parameter)
5244    */
5245   self.cookies = function(name, value) {
5246     var cookieLength, cookieArray, cookie, i, index;
5247
5248     if (name) {
5249       if (value === undefined) {
5250         rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
5251                                 ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
5252       } else {
5253         if (isString(value)) {
5254           cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
5255                                 ';path=' + cookiePath).length + 1;
5256
5257           // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
5258           // - 300 cookies
5259           // - 20 cookies per unique domain
5260           // - 4096 bytes per cookie
5261           if (cookieLength > 4096) {
5262             $log.warn("Cookie '" + name +
5263               "' possibly not set or overflowed because it was too large (" +
5264               cookieLength + " > 4096 bytes)!");
5265           }
5266         }
5267       }
5268     } else {
5269       if (rawDocument.cookie !== lastCookieString) {
5270         lastCookieString = rawDocument.cookie;
5271         cookieArray = lastCookieString.split("; ");
5272         lastCookies = {};
5273
5274         for (i = 0; i < cookieArray.length; i++) {
5275           cookie = cookieArray[i];
5276           index = cookie.indexOf('=');
5277           if (index > 0) { //ignore nameless cookies
5278             name = safeDecodeURIComponent(cookie.substring(0, index));
5279             // the first value that is seen for a cookie is the most
5280             // specific one.  values for the same cookie name that
5281             // follow are for less specific paths.
5282             if (lastCookies[name] === undefined) {
5283               lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
5284             }
5285           }
5286         }
5287       }
5288       return lastCookies;
5289     }
5290   };
5291
5292
5293   /**
5294    * @name $browser#defer
5295    * @param {function()} fn A function, who's execution should be deferred.
5296    * @param {number=} [delay=0] of milliseconds to defer the function execution.
5297    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5298    *
5299    * @description
5300    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5301    *
5302    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5303    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5304    * via `$browser.defer.flush()`.
5305    *
5306    */
5307   self.defer = function(fn, delay) {
5308     var timeoutId;
5309     outstandingRequestCount++;
5310     timeoutId = setTimeout(function() {
5311       delete pendingDeferIds[timeoutId];
5312       completeOutstandingRequest(fn);
5313     }, delay || 0);
5314     pendingDeferIds[timeoutId] = true;
5315     return timeoutId;
5316   };
5317
5318
5319   /**
5320    * @name $browser#defer.cancel
5321    *
5322    * @description
5323    * Cancels a deferred task identified with `deferId`.
5324    *
5325    * @param {*} deferId Token returned by the `$browser.defer` function.
5326    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5327    *                    canceled.
5328    */
5329   self.defer.cancel = function(deferId) {
5330     if (pendingDeferIds[deferId]) {
5331       delete pendingDeferIds[deferId];
5332       clearTimeout(deferId);
5333       completeOutstandingRequest(noop);
5334       return true;
5335     }
5336     return false;
5337   };
5338
5339 }
5340
5341 function $BrowserProvider() {
5342   this.$get = ['$window', '$log', '$sniffer', '$document',
5343       function($window, $log, $sniffer, $document) {
5344         return new Browser($window, $document, $log, $sniffer);
5345       }];
5346 }
5347
5348 /**
5349  * @ngdoc service
5350  * @name $cacheFactory
5351  *
5352  * @description
5353  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5354  * them.
5355  *
5356  * ```js
5357  *
5358  *  var cache = $cacheFactory('cacheId');
5359  *  expect($cacheFactory.get('cacheId')).toBe(cache);
5360  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5361  *
5362  *  cache.put("key", "value");
5363  *  cache.put("another key", "another value");
5364  *
5365  *  // We've specified no options on creation
5366  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5367  *
5368  * ```
5369  *
5370  *
5371  * @param {string} cacheId Name or id of the newly created cache.
5372  * @param {object=} options Options object that specifies the cache behavior. Properties:
5373  *
5374  *   - `{number=}` `capacity` — turns the cache into LRU cache.
5375  *
5376  * @returns {object} Newly created cache object with the following set of methods:
5377  *
5378  * - `{object}` `info()` — Returns id, size, and options of cache.
5379  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5380  *   it.
5381  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5382  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5383  * - `{void}` `removeAll()` — Removes all cached values.
5384  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5385  *
5386  * @example
5387    <example module="cacheExampleApp">
5388      <file name="index.html">
5389        <div ng-controller="CacheController">
5390          <input ng-model="newCacheKey" placeholder="Key">
5391          <input ng-model="newCacheValue" placeholder="Value">
5392          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5393
5394          <p ng-if="keys.length">Cached Values</p>
5395          <div ng-repeat="key in keys">
5396            <span ng-bind="key"></span>
5397            <span>: </span>
5398            <b ng-bind="cache.get(key)"></b>
5399          </div>
5400
5401          <p>Cache Info</p>
5402          <div ng-repeat="(key, value) in cache.info()">
5403            <span ng-bind="key"></span>
5404            <span>: </span>
5405            <b ng-bind="value"></b>
5406          </div>
5407        </div>
5408      </file>
5409      <file name="script.js">
5410        angular.module('cacheExampleApp', []).
5411          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
5412            $scope.keys = [];
5413            $scope.cache = $cacheFactory('cacheId');
5414            $scope.put = function(key, value) {
5415              if ($scope.cache.get(key) === undefined) {
5416                $scope.keys.push(key);
5417              }
5418              $scope.cache.put(key, value === undefined ? null : value);
5419            };
5420          }]);
5421      </file>
5422      <file name="style.css">
5423        p {
5424          margin: 10px 0 3px;
5425        }
5426      </file>
5427    </example>
5428  */
5429 function $CacheFactoryProvider() {
5430
5431   this.$get = function() {
5432     var caches = {};
5433
5434     function cacheFactory(cacheId, options) {
5435       if (cacheId in caches) {
5436         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
5437       }
5438
5439       var size = 0,
5440           stats = extend({}, options, {id: cacheId}),
5441           data = {},
5442           capacity = (options && options.capacity) || Number.MAX_VALUE,
5443           lruHash = {},
5444           freshEnd = null,
5445           staleEnd = null;
5446
5447       /**
5448        * @ngdoc type
5449        * @name $cacheFactory.Cache
5450        *
5451        * @description
5452        * A cache object used to store and retrieve data, primarily used by
5453        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
5454        * templates and other data.
5455        *
5456        * ```js
5457        *  angular.module('superCache')
5458        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
5459        *      return $cacheFactory('super-cache');
5460        *    }]);
5461        * ```
5462        *
5463        * Example test:
5464        *
5465        * ```js
5466        *  it('should behave like a cache', inject(function(superCache) {
5467        *    superCache.put('key', 'value');
5468        *    superCache.put('another key', 'another value');
5469        *
5470        *    expect(superCache.info()).toEqual({
5471        *      id: 'super-cache',
5472        *      size: 2
5473        *    });
5474        *
5475        *    superCache.remove('another key');
5476        *    expect(superCache.get('another key')).toBeUndefined();
5477        *
5478        *    superCache.removeAll();
5479        *    expect(superCache.info()).toEqual({
5480        *      id: 'super-cache',
5481        *      size: 0
5482        *    });
5483        *  }));
5484        * ```
5485        */
5486       return caches[cacheId] = {
5487
5488         /**
5489          * @ngdoc method
5490          * @name $cacheFactory.Cache#put
5491          * @kind function
5492          *
5493          * @description
5494          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
5495          * retrieved later, and incrementing the size of the cache if the key was not already
5496          * present in the cache. If behaving like an LRU cache, it will also remove stale
5497          * entries from the set.
5498          *
5499          * It will not insert undefined values into the cache.
5500          *
5501          * @param {string} key the key under which the cached data is stored.
5502          * @param {*} value the value to store alongside the key. If it is undefined, the key
5503          *    will not be stored.
5504          * @returns {*} the value stored.
5505          */
5506         put: function(key, value) {
5507           if (capacity < Number.MAX_VALUE) {
5508             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
5509
5510             refresh(lruEntry);
5511           }
5512
5513           if (isUndefined(value)) return;
5514           if (!(key in data)) size++;
5515           data[key] = value;
5516
5517           if (size > capacity) {
5518             this.remove(staleEnd.key);
5519           }
5520
5521           return value;
5522         },
5523
5524         /**
5525          * @ngdoc method
5526          * @name $cacheFactory.Cache#get
5527          * @kind function
5528          *
5529          * @description
5530          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
5531          *
5532          * @param {string} key the key of the data to be retrieved
5533          * @returns {*} the value stored.
5534          */
5535         get: function(key) {
5536           if (capacity < Number.MAX_VALUE) {
5537             var lruEntry = lruHash[key];
5538
5539             if (!lruEntry) return;
5540
5541             refresh(lruEntry);
5542           }
5543
5544           return data[key];
5545         },
5546
5547
5548         /**
5549          * @ngdoc method
5550          * @name $cacheFactory.Cache#remove
5551          * @kind function
5552          *
5553          * @description
5554          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
5555          *
5556          * @param {string} key the key of the entry to be removed
5557          */
5558         remove: function(key) {
5559           if (capacity < Number.MAX_VALUE) {
5560             var lruEntry = lruHash[key];
5561
5562             if (!lruEntry) return;
5563
5564             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
5565             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
5566             link(lruEntry.n,lruEntry.p);
5567
5568             delete lruHash[key];
5569           }
5570
5571           delete data[key];
5572           size--;
5573         },
5574
5575
5576         /**
5577          * @ngdoc method
5578          * @name $cacheFactory.Cache#removeAll
5579          * @kind function
5580          *
5581          * @description
5582          * Clears the cache object of any entries.
5583          */
5584         removeAll: function() {
5585           data = {};
5586           size = 0;
5587           lruHash = {};
5588           freshEnd = staleEnd = null;
5589         },
5590
5591
5592         /**
5593          * @ngdoc method
5594          * @name $cacheFactory.Cache#destroy
5595          * @kind function
5596          *
5597          * @description
5598          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
5599          * removing it from the {@link $cacheFactory $cacheFactory} set.
5600          */
5601         destroy: function() {
5602           data = null;
5603           stats = null;
5604           lruHash = null;
5605           delete caches[cacheId];
5606         },
5607
5608
5609         /**
5610          * @ngdoc method
5611          * @name $cacheFactory.Cache#info
5612          * @kind function
5613          *
5614          * @description
5615          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5616          *
5617          * @returns {object} an object with the following properties:
5618          *   <ul>
5619          *     <li>**id**: the id of the cache instance</li>
5620          *     <li>**size**: the number of entries kept in the cache instance</li>
5621          *     <li>**...**: any additional properties from the options object when creating the
5622          *       cache.</li>
5623          *   </ul>
5624          */
5625         info: function() {
5626           return extend({}, stats, {size: size});
5627         }
5628       };
5629
5630
5631       /**
5632        * makes the `entry` the freshEnd of the LRU linked list
5633        */
5634       function refresh(entry) {
5635         if (entry != freshEnd) {
5636           if (!staleEnd) {
5637             staleEnd = entry;
5638           } else if (staleEnd == entry) {
5639             staleEnd = entry.n;
5640           }
5641
5642           link(entry.n, entry.p);
5643           link(entry, freshEnd);
5644           freshEnd = entry;
5645           freshEnd.n = null;
5646         }
5647       }
5648
5649
5650       /**
5651        * bidirectionally links two entries of the LRU linked list
5652        */
5653       function link(nextEntry, prevEntry) {
5654         if (nextEntry != prevEntry) {
5655           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5656           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5657         }
5658       }
5659     }
5660
5661
5662   /**
5663    * @ngdoc method
5664    * @name $cacheFactory#info
5665    *
5666    * @description
5667    * Get information about all the caches that have been created
5668    *
5669    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5670    */
5671     cacheFactory.info = function() {
5672       var info = {};
5673       forEach(caches, function(cache, cacheId) {
5674         info[cacheId] = cache.info();
5675       });
5676       return info;
5677     };
5678
5679
5680   /**
5681    * @ngdoc method
5682    * @name $cacheFactory#get
5683    *
5684    * @description
5685    * Get access to a cache object by the `cacheId` used when it was created.
5686    *
5687    * @param {string} cacheId Name or id of a cache to access.
5688    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5689    */
5690     cacheFactory.get = function(cacheId) {
5691       return caches[cacheId];
5692     };
5693
5694
5695     return cacheFactory;
5696   };
5697 }
5698
5699 /**
5700  * @ngdoc service
5701  * @name $templateCache
5702  *
5703  * @description
5704  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5705  * can load templates directly into the cache in a `script` tag, or by consuming the
5706  * `$templateCache` service directly.
5707  *
5708  * Adding via the `script` tag:
5709  *
5710  * ```html
5711  *   <script type="text/ng-template" id="templateId.html">
5712  *     <p>This is the content of the template</p>
5713  *   </script>
5714  * ```
5715  *
5716  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5717  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
5718  * element with ng-app attribute), otherwise the template will be ignored.
5719  *
5720  * Adding via the `$templateCache` service:
5721  *
5722  * ```js
5723  * var myApp = angular.module('myApp', []);
5724  * myApp.run(function($templateCache) {
5725  *   $templateCache.put('templateId.html', 'This is the content of the template');
5726  * });
5727  * ```
5728  *
5729  * To retrieve the template later, simply use it in your HTML:
5730  * ```html
5731  * <div ng-include=" 'templateId.html' "></div>
5732  * ```
5733  *
5734  * or get it via Javascript:
5735  * ```js
5736  * $templateCache.get('templateId.html')
5737  * ```
5738  *
5739  * See {@link ng.$cacheFactory $cacheFactory}.
5740  *
5741  */
5742 function $TemplateCacheProvider() {
5743   this.$get = ['$cacheFactory', function($cacheFactory) {
5744     return $cacheFactory('templates');
5745   }];
5746 }
5747
5748 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5749  *     Any commits to this file should be reviewed with security in mind.  *
5750  *   Changes to this file can potentially create security vulnerabilities. *
5751  *          An approval from 2 Core members with history of modifying      *
5752  *                         this file is required.                          *
5753  *                                                                         *
5754  *  Does the change somehow allow for arbitrary javascript to be executed? *
5755  *    Or allows for someone to change the prototype of built-in objects?   *
5756  *     Or gives undesired access to variables likes document or window?    *
5757  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5758
5759 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5760  *
5761  * DOM-related variables:
5762  *
5763  * - "node" - DOM Node
5764  * - "element" - DOM Element or Node
5765  * - "$node" or "$element" - jqLite-wrapped node or element
5766  *
5767  *
5768  * Compiler related stuff:
5769  *
5770  * - "linkFn" - linking fn of a single directive
5771  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5772  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5773  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5774  */
5775
5776
5777 /**
5778  * @ngdoc service
5779  * @name $compile
5780  * @kind function
5781  *
5782  * @description
5783  * Compiles an HTML string or DOM into a template and produces a template function, which
5784  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5785  *
5786  * The compilation is a process of walking the DOM tree and matching DOM elements to
5787  * {@link ng.$compileProvider#directive directives}.
5788  *
5789  * <div class="alert alert-warning">
5790  * **Note:** This document is an in-depth reference of all directive options.
5791  * For a gentle introduction to directives with examples of common use cases,
5792  * see the {@link guide/directive directive guide}.
5793  * </div>
5794  *
5795  * ## Comprehensive Directive API
5796  *
5797  * There are many different options for a directive.
5798  *
5799  * The difference resides in the return value of the factory function.
5800  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5801  * or just the `postLink` function (all other properties will have the default values).
5802  *
5803  * <div class="alert alert-success">
5804  * **Best Practice:** It's recommended to use the "directive definition object" form.
5805  * </div>
5806  *
5807  * Here's an example directive declared with a Directive Definition Object:
5808  *
5809  * ```js
5810  *   var myModule = angular.module(...);
5811  *
5812  *   myModule.directive('directiveName', function factory(injectables) {
5813  *     var directiveDefinitionObject = {
5814  *       priority: 0,
5815  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
5816  *       // or
5817  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5818  *       transclude: false,
5819  *       restrict: 'A',
5820  *       templateNamespace: 'html',
5821  *       scope: false,
5822  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5823  *       controllerAs: 'stringAlias',
5824  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5825  *       compile: function compile(tElement, tAttrs, transclude) {
5826  *         return {
5827  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5828  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5829  *         }
5830  *         // or
5831  *         // return function postLink( ... ) { ... }
5832  *       },
5833  *       // or
5834  *       // link: {
5835  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5836  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5837  *       // }
5838  *       // or
5839  *       // link: function postLink( ... ) { ... }
5840  *     };
5841  *     return directiveDefinitionObject;
5842  *   });
5843  * ```
5844  *
5845  * <div class="alert alert-warning">
5846  * **Note:** Any unspecified options will use the default value. You can see the default values below.
5847  * </div>
5848  *
5849  * Therefore the above can be simplified as:
5850  *
5851  * ```js
5852  *   var myModule = angular.module(...);
5853  *
5854  *   myModule.directive('directiveName', function factory(injectables) {
5855  *     var directiveDefinitionObject = {
5856  *       link: function postLink(scope, iElement, iAttrs) { ... }
5857  *     };
5858  *     return directiveDefinitionObject;
5859  *     // or
5860  *     // return function postLink(scope, iElement, iAttrs) { ... }
5861  *   });
5862  * ```
5863  *
5864  *
5865  *
5866  * ### Directive Definition Object
5867  *
5868  * The directive definition object provides instructions to the {@link ng.$compile
5869  * compiler}. The attributes are:
5870  *
5871  * #### `multiElement`
5872  * When this property is set to true, the HTML compiler will collect DOM nodes between
5873  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
5874  * together as the directive elements. It is recommended that this feature be used on directives
5875  * which are not strictly behavioural (such as {@link ngClick}), and which
5876  * do not manipulate or replace child nodes (such as {@link ngInclude}).
5877  *
5878  * #### `priority`
5879  * When there are multiple directives defined on a single DOM element, sometimes it
5880  * is necessary to specify the order in which the directives are applied. The `priority` is used
5881  * to sort the directives before their `compile` functions get called. Priority is defined as a
5882  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5883  * are also run in priority order, but post-link functions are run in reverse order. The order
5884  * of directives with the same priority is undefined. The default priority is `0`.
5885  *
5886  * #### `terminal`
5887  * If set to true then the current `priority` will be the last set of directives
5888  * which will execute (any directives at the current priority will still execute
5889  * as the order of execution on same `priority` is undefined). Note that expressions
5890  * and other directives used in the directive's template will also be excluded from execution.
5891  *
5892  * #### `scope`
5893  * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5894  * same element request a new scope, only one new scope is created. The new scope rule does not
5895  * apply for the root of the template since the root of the template always gets a new scope.
5896  *
5897  * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5898  * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5899  * when creating reusable components, which should not accidentally read or modify data in the
5900  * parent scope.
5901  *
5902  * The 'isolate' scope takes an object hash which defines a set of local scope properties
5903  * derived from the parent scope. These local properties are useful for aliasing values for
5904  * templates. Locals definition is a hash of local scope property to its source:
5905  *
5906  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5907  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5908  *   attribute name is assumed to be the same as the local name.
5909  *   Given `<widget my-attr="hello {{name}}">` and widget definition
5910  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5911  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5912  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5913  *   component scope).
5914  *
5915  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5916  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5917  *   name is specified then the attribute name is assumed to be the same as the local name.
5918  *   Given `<widget my-attr="parentModel">` and widget definition of
5919  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5920  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5921  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5922  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5923  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
5924  *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
5925  *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
5926  *
5927  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5928  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5929  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5930  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5931  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5932  *   pass data from the isolated scope via an expression to the parent scope, this can be
5933  *   done by passing a map of local variable names and values into the expression wrapper fn.
5934  *   For example, if the expression is `increment(amount)` then we can specify the amount value
5935  *   by calling the `localFn` as `localFn({amount: 22})`.
5936  *
5937  *
5938  * #### `bindToController`
5939  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
5940  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
5941  * is instantiated, the initial values of the isolate scope bindings are already available.
5942  *
5943  * #### `controller`
5944  * Controller constructor function. The controller is instantiated before the
5945  * pre-linking phase and it is shared with other directives (see
5946  * `require` attribute). This allows the directives to communicate with each other and augment
5947  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5948  *
5949  * * `$scope` - Current scope associated with the element
5950  * * `$element` - Current element
5951  * * `$attrs` - Current attributes object for the element
5952  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
5953  *   `function([scope], cloneLinkingFn, futureParentElement)`.
5954  *    * `scope`: optional argument to override the scope.
5955  *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
5956  *    * `futureParentElement`:
5957  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
5958  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
5959  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
5960  *          and when the `cloneLinkinFn` is passed,
5961  *          as those elements need to created and cloned in a special way when they are defined outside their
5962  *          usual containers (e.g. like `<svg>`).
5963  *        * See also the `directive.templateNamespace` property.
5964  *
5965  *
5966  * #### `require`
5967  * Require another directive and inject its controller as the fourth argument to the linking function. The
5968  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5969  * injected argument will be an array in corresponding order. If no such directive can be
5970  * found, or if the directive does not have a controller, then an error is raised (unless no link function
5971  * is specified, in which case error checking is skipped). The name can be prefixed with:
5972  *
5973  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5974  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5975  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5976  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5977  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5978  *   `null` to the `link` fn if not found.
5979  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
5980  *   `null` to the `link` fn if not found.
5981  *
5982  *
5983  * #### `controllerAs`
5984  * Controller alias at the directive scope. An alias for the controller so it
5985  * can be referenced at the directive template. The directive needs to define a scope for this
5986  * configuration to be used. Useful in the case when directive is used as component.
5987  *
5988  *
5989  * #### `restrict`
5990  * String of subset of `EACM` which restricts the directive to a specific directive
5991  * declaration style. If omitted, the defaults (elements and attributes) are used.
5992  *
5993  * * `E` - Element name (default): `<my-directive></my-directive>`
5994  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5995  * * `C` - Class: `<div class="my-directive: exp;"></div>`
5996  * * `M` - Comment: `<!-- directive: my-directive exp -->`
5997  *
5998  *
5999  * #### `templateNamespace`
6000  * String representing the document type used by the markup in the template.
6001  * AngularJS needs this information as those elements need to be created and cloned
6002  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6003  *
6004  * * `html` - All root nodes in the template are HTML. Root nodes may also be
6005  *   top-level elements such as `<svg>` or `<math>`.
6006  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6007  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6008  *
6009  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6010  *
6011  * #### `template`
6012  * HTML markup that may:
6013  * * Replace the contents of the directive's element (default).
6014  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6015  * * Wrap the contents of the directive's element (if `transclude` is true).
6016  *
6017  * Value may be:
6018  *
6019  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6020  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6021  *   function api below) and returns a string value.
6022  *
6023  *
6024  * #### `templateUrl`
6025  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6026  *
6027  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6028  * for later when the template has been resolved.  In the meantime it will continue to compile and link
6029  * sibling and parent elements as though this element had not contained any directives.
6030  *
6031  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6032  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6033  * case when only one deeply nested directive has `templateUrl`.
6034  *
6035  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6036  *
6037  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6038  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6039  * a string value representing the url.  In either case, the template URL is passed through {@link
6040  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6041  *
6042  *
6043  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6044  * specify what the template should replace. Defaults to `false`.
6045  *
6046  * * `true` - the template will replace the directive's element.
6047  * * `false` - the template will replace the contents of the directive's element.
6048  *
6049  * The replacement process migrates all of the attributes / classes from the old element to the new
6050  * one. See the {@link guide/directive#template-expanding-directive
6051  * Directives Guide} for an example.
6052  *
6053  * There are very few scenarios where element replacement is required for the application function,
6054  * the main one being reusable custom components that are used within SVG contexts
6055  * (because SVG doesn't work with custom elements in the DOM tree).
6056  *
6057  * #### `transclude`
6058  * Extract the contents of the element where the directive appears and make it available to the directive.
6059  * The contents are compiled and provided to the directive as a **transclusion function**. See the
6060  * {@link $compile#transclusion Transclusion} section below.
6061  *
6062  * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6063  * directive's element or the entire element:
6064  *
6065  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6066  * * `'element'` - transclude the whole of the directive's element including any directives on this
6067  *   element that defined at a lower priority than this directive. When used, the `template`
6068  *   property is ignored.
6069  *
6070  *
6071  * #### `compile`
6072  *
6073  * ```js
6074  *   function compile(tElement, tAttrs, transclude) { ... }
6075  * ```
6076  *
6077  * The compile function deals with transforming the template DOM. Since most directives do not do
6078  * template transformation, it is not used often. The compile function takes the following arguments:
6079  *
6080  *   * `tElement` - template element - The element where the directive has been declared. It is
6081  *     safe to do template transformation on the element and child elements only.
6082  *
6083  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6084  *     between all directive compile functions.
6085  *
6086  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6087  *
6088  * <div class="alert alert-warning">
6089  * **Note:** The template instance and the link instance may be different objects if the template has
6090  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6091  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6092  * should be done in a linking function rather than in a compile function.
6093  * </div>
6094
6095  * <div class="alert alert-warning">
6096  * **Note:** The compile function cannot handle directives that recursively use themselves in their
6097  * own templates or compile functions. Compiling these directives results in an infinite loop and a
6098  * stack overflow errors.
6099  *
6100  * This can be avoided by manually using $compile in the postLink function to imperatively compile
6101  * a directive's template instead of relying on automatic template compilation via `template` or
6102  * `templateUrl` declaration or manual compilation inside the compile function.
6103  * </div>
6104  *
6105  * <div class="alert alert-error">
6106  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6107  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6108  *   to the link function instead.
6109  * </div>
6110
6111  * A compile function can have a return value which can be either a function or an object.
6112  *
6113  * * returning a (post-link) function - is equivalent to registering the linking function via the
6114  *   `link` property of the config object when the compile function is empty.
6115  *
6116  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6117  *   control when a linking function should be called during the linking phase. See info about
6118  *   pre-linking and post-linking functions below.
6119  *
6120  *
6121  * #### `link`
6122  * This property is used only if the `compile` property is not defined.
6123  *
6124  * ```js
6125  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6126  * ```
6127  *
6128  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6129  * executed after the template has been cloned. This is where most of the directive logic will be
6130  * put.
6131  *
6132  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6133  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6134  *
6135  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6136  *     manipulate the children of the element only in `postLink` function since the children have
6137  *     already been linked.
6138  *
6139  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6140  *     between all directive linking functions.
6141  *
6142  *   * `controller` - a controller instance - A controller instance if at least one directive on the
6143  *     element defines a controller. The controller is shared among all the directives, which allows
6144  *     the directives to use the controllers as a communication channel.
6145  *
6146  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6147  *     This is the same as the `$transclude`
6148  *     parameter of directive controllers, see there for details.
6149  *     `function([scope], cloneLinkingFn, futureParentElement)`.
6150  *
6151  * #### Pre-linking function
6152  *
6153  * Executed before the child elements are linked. Not safe to do DOM transformation since the
6154  * compiler linking function will fail to locate the correct elements for linking.
6155  *
6156  * #### Post-linking function
6157  *
6158  * Executed after the child elements are linked.
6159  *
6160  * Note that child elements that contain `templateUrl` directives will not have been compiled
6161  * and linked since they are waiting for their template to load asynchronously and their own
6162  * compilation and linking has been suspended until that occurs.
6163  *
6164  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6165  * for their async templates to be resolved.
6166  *
6167  *
6168  * ### Transclusion
6169  *
6170  * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
6171  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6172  * scope from where they were taken.
6173  *
6174  * Transclusion is used (often with {@link ngTransclude}) to insert the
6175  * original contents of a directive's element into a specified place in the template of the directive.
6176  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6177  * content has access to the properties on the scope from which it was taken, even if the directive
6178  * has isolated scope.
6179  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6180  *
6181  * This makes it possible for the widget to have private state for its template, while the transcluded
6182  * content has access to its originating scope.
6183  *
6184  * <div class="alert alert-warning">
6185  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6186  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6187  * Testing Transclusion Directives}.
6188  * </div>
6189  *
6190  * #### Transclusion Functions
6191  *
6192  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6193  * function** to the directive's `link` function and `controller`. This transclusion function is a special
6194  * **linking function** that will return the compiled contents linked to a new transclusion scope.
6195  *
6196  * <div class="alert alert-info">
6197  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6198  * ngTransclude will deal with it for us.
6199  * </div>
6200  *
6201  * If you want to manually control the insertion and removal of the transcluded content in your directive
6202  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6203  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6204  *
6205  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6206  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6207  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6208  *
6209  * <div class="alert alert-info">
6210  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6211  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6212  * </div>
6213  *
6214  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6215  * attach function**:
6216  *
6217  * ```js
6218  * var transcludedContent, transclusionScope;
6219  *
6220  * $transclude(function(clone, scope) {
6221  *   element.append(clone);
6222  *   transcludedContent = clone;
6223  *   transclusionScope = scope;
6224  * });
6225  * ```
6226  *
6227  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6228  * associated transclusion scope:
6229  *
6230  * ```js
6231  * transcludedContent.remove();
6232  * transclusionScope.$destroy();
6233  * ```
6234  *
6235  * <div class="alert alert-info">
6236  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6237  * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
6238  * then you are also responsible for calling `$destroy` on the transclusion scope.
6239  * </div>
6240  *
6241  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6242  * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6243  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6244  *
6245  *
6246  * #### Transclusion Scopes
6247  *
6248  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6249  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6250  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6251  * was taken.
6252  *
6253  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6254  * like this:
6255  *
6256  * ```html
6257  * <div ng-app>
6258  *   <div isolate>
6259  *     <div transclusion>
6260  *     </div>
6261  *   </div>
6262  * </div>
6263  * ```
6264  *
6265  * The `$parent` scope hierarchy will look like this:
6266  *
6267  * ```
6268  * - $rootScope
6269  *   - isolate
6270  *     - transclusion
6271  * ```
6272  *
6273  * but the scopes will inherit prototypically from different scopes to their `$parent`.
6274  *
6275  * ```
6276  * - $rootScope
6277  *   - transclusion
6278  * - isolate
6279  * ```
6280  *
6281  *
6282  * ### Attributes
6283  *
6284  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6285  * `link()` or `compile()` functions. It has a variety of uses.
6286  *
6287  * accessing *Normalized attribute names:*
6288  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6289  * the attributes object allows for normalized access to
6290  *   the attributes.
6291  *
6292  * * *Directive inter-communication:* All directives share the same instance of the attributes
6293  *   object which allows the directives to use the attributes object as inter directive
6294  *   communication.
6295  *
6296  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6297  *   allowing other directives to read the interpolated value.
6298  *
6299  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6300  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6301  *   the only way to easily get the actual value because during the linking phase the interpolation
6302  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6303  *
6304  * ```js
6305  * function linkingFn(scope, elm, attrs, ctrl) {
6306  *   // get the attribute value
6307  *   console.log(attrs.ngModel);
6308  *
6309  *   // change the attribute
6310  *   attrs.$set('ngModel', 'new value');
6311  *
6312  *   // observe changes to interpolated attribute
6313  *   attrs.$observe('ngModel', function(value) {
6314  *     console.log('ngModel has changed value to ' + value);
6315  *   });
6316  * }
6317  * ```
6318  *
6319  * ## Example
6320  *
6321  * <div class="alert alert-warning">
6322  * **Note**: Typically directives are registered with `module.directive`. The example below is
6323  * to illustrate how `$compile` works.
6324  * </div>
6325  *
6326  <example module="compileExample">
6327    <file name="index.html">
6328     <script>
6329       angular.module('compileExample', [], function($compileProvider) {
6330         // configure new 'compile' directive by passing a directive
6331         // factory function. The factory function injects the '$compile'
6332         $compileProvider.directive('compile', function($compile) {
6333           // directive factory creates a link function
6334           return function(scope, element, attrs) {
6335             scope.$watch(
6336               function(scope) {
6337                  // watch the 'compile' expression for changes
6338                 return scope.$eval(attrs.compile);
6339               },
6340               function(value) {
6341                 // when the 'compile' expression changes
6342                 // assign it into the current DOM
6343                 element.html(value);
6344
6345                 // compile the new DOM and link it to the current
6346                 // scope.
6347                 // NOTE: we only compile .childNodes so that
6348                 // we don't get into infinite loop compiling ourselves
6349                 $compile(element.contents())(scope);
6350               }
6351             );
6352           };
6353         });
6354       })
6355       .controller('GreeterController', ['$scope', function($scope) {
6356         $scope.name = 'Angular';
6357         $scope.html = 'Hello {{name}}';
6358       }]);
6359     </script>
6360     <div ng-controller="GreeterController">
6361       <input ng-model="name"> <br>
6362       <textarea ng-model="html"></textarea> <br>
6363       <div compile="html"></div>
6364     </div>
6365    </file>
6366    <file name="protractor.js" type="protractor">
6367      it('should auto compile', function() {
6368        var textarea = $('textarea');
6369        var output = $('div[compile]');
6370        // The initial state reads 'Hello Angular'.
6371        expect(output.getText()).toBe('Hello Angular');
6372        textarea.clear();
6373        textarea.sendKeys('{{name}}!');
6374        expect(output.getText()).toBe('Angular!');
6375      });
6376    </file>
6377  </example>
6378
6379  *
6380  *
6381  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
6382  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
6383  *
6384  * <div class="alert alert-error">
6385  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
6386  *   e.g. will not use the right outer scope. Please pass the transclude function as a
6387  *   `parentBoundTranscludeFn` to the link function instead.
6388  * </div>
6389  *
6390  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
6391  *                 root element(s), not their children)
6392  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
6393  * (a DOM element/tree) to a scope. Where:
6394  *
6395  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
6396  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
6397  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
6398  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
6399  *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
6400  *
6401  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
6402  *      * `scope` - is the current scope with which the linking function is working with.
6403  *
6404  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
6405  *  keys may be used to control linking behavior:
6406  *
6407  *      * `parentBoundTranscludeFn` - the transclude function made available to
6408  *        directives; if given, it will be passed through to the link functions of
6409  *        directives found in `element` during compilation.
6410  *      * `transcludeControllers` - an object hash with keys that map controller names
6411  *        to controller instances; if given, it will make the controllers
6412  *        available to directives.
6413  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6414  *        the cloned elements; only needed for transcludes that are allowed to contain non html
6415  *        elements (e.g. SVG elements). See also the directive.controller property.
6416  *
6417  * Calling the linking function returns the element of the template. It is either the original
6418  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
6419  *
6420  * After linking the view is not updated until after a call to $digest which typically is done by
6421  * Angular automatically.
6422  *
6423  * If you need access to the bound view, there are two ways to do it:
6424  *
6425  * - If you are not asking the linking function to clone the template, create the DOM element(s)
6426  *   before you send them to the compiler and keep this reference around.
6427  *   ```js
6428  *     var element = $compile('<p>{{total}}</p>')(scope);
6429  *   ```
6430  *
6431  * - if on the other hand, you need the element to be cloned, the view reference from the original
6432  *   example would not point to the clone, but rather to the original template that was cloned. In
6433  *   this case, you can access the clone via the cloneAttachFn:
6434  *   ```js
6435  *     var templateElement = angular.element('<p>{{total}}</p>'),
6436  *         scope = ....;
6437  *
6438  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
6439  *       //attach the clone to DOM document at the right place
6440  *     });
6441  *
6442  *     //now we have reference to the cloned DOM via `clonedElement`
6443  *   ```
6444  *
6445  *
6446  * For information on how the compiler works, see the
6447  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
6448  */
6449
6450 var $compileMinErr = minErr('$compile');
6451
6452 /**
6453  * @ngdoc provider
6454  * @name $compileProvider
6455  *
6456  * @description
6457  */
6458 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
6459 function $CompileProvider($provide, $$sanitizeUriProvider) {
6460   var hasDirectives = {},
6461       Suffix = 'Directive',
6462       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
6463       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
6464       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
6465       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
6466
6467   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
6468   // The assumption is that future DOM event attribute names will begin with
6469   // 'on' and be composed of only English letters.
6470   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
6471
6472   function parseIsolateBindings(scope, directiveName) {
6473     var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
6474
6475     var bindings = {};
6476
6477     forEach(scope, function(definition, scopeName) {
6478       var match = definition.match(LOCAL_REGEXP);
6479
6480       if (!match) {
6481         throw $compileMinErr('iscp',
6482             "Invalid isolate scope definition for directive '{0}'." +
6483             " Definition: {... {1}: '{2}' ...}",
6484             directiveName, scopeName, definition);
6485       }
6486
6487       bindings[scopeName] = {
6488         mode: match[1][0],
6489         collection: match[2] === '*',
6490         optional: match[3] === '?',
6491         attrName: match[4] || scopeName
6492       };
6493     });
6494
6495     return bindings;
6496   }
6497
6498   /**
6499    * @ngdoc method
6500    * @name $compileProvider#directive
6501    * @kind function
6502    *
6503    * @description
6504    * Register a new directive with the compiler.
6505    *
6506    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
6507    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
6508    *    names and the values are the factories.
6509    * @param {Function|Array} directiveFactory An injectable directive factory function. See
6510    *    {@link guide/directive} for more info.
6511    * @returns {ng.$compileProvider} Self for chaining.
6512    */
6513    this.directive = function registerDirective(name, directiveFactory) {
6514     assertNotHasOwnProperty(name, 'directive');
6515     if (isString(name)) {
6516       assertArg(directiveFactory, 'directiveFactory');
6517       if (!hasDirectives.hasOwnProperty(name)) {
6518         hasDirectives[name] = [];
6519         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
6520           function($injector, $exceptionHandler) {
6521             var directives = [];
6522             forEach(hasDirectives[name], function(directiveFactory, index) {
6523               try {
6524                 var directive = $injector.invoke(directiveFactory);
6525                 if (isFunction(directive)) {
6526                   directive = { compile: valueFn(directive) };
6527                 } else if (!directive.compile && directive.link) {
6528                   directive.compile = valueFn(directive.link);
6529                 }
6530                 directive.priority = directive.priority || 0;
6531                 directive.index = index;
6532                 directive.name = directive.name || name;
6533                 directive.require = directive.require || (directive.controller && directive.name);
6534                 directive.restrict = directive.restrict || 'EA';
6535                 if (isObject(directive.scope)) {
6536                   directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name);
6537                 }
6538                 directives.push(directive);
6539               } catch (e) {
6540                 $exceptionHandler(e);
6541               }
6542             });
6543             return directives;
6544           }]);
6545       }
6546       hasDirectives[name].push(directiveFactory);
6547     } else {
6548       forEach(name, reverseParams(registerDirective));
6549     }
6550     return this;
6551   };
6552
6553
6554   /**
6555    * @ngdoc method
6556    * @name $compileProvider#aHrefSanitizationWhitelist
6557    * @kind function
6558    *
6559    * @description
6560    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6561    * urls during a[href] sanitization.
6562    *
6563    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
6564    *
6565    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
6566    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
6567    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6568    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6569    *
6570    * @param {RegExp=} regexp New regexp to whitelist urls with.
6571    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6572    *    chaining otherwise.
6573    */
6574   this.aHrefSanitizationWhitelist = function(regexp) {
6575     if (isDefined(regexp)) {
6576       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
6577       return this;
6578     } else {
6579       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
6580     }
6581   };
6582
6583
6584   /**
6585    * @ngdoc method
6586    * @name $compileProvider#imgSrcSanitizationWhitelist
6587    * @kind function
6588    *
6589    * @description
6590    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6591    * urls during img[src] sanitization.
6592    *
6593    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
6594    *
6595    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
6596    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
6597    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6598    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6599    *
6600    * @param {RegExp=} regexp New regexp to whitelist urls with.
6601    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6602    *    chaining otherwise.
6603    */
6604   this.imgSrcSanitizationWhitelist = function(regexp) {
6605     if (isDefined(regexp)) {
6606       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
6607       return this;
6608     } else {
6609       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
6610     }
6611   };
6612
6613   /**
6614    * @ngdoc method
6615    * @name  $compileProvider#debugInfoEnabled
6616    *
6617    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
6618    * current debugInfoEnabled state
6619    * @returns {*} current value if used as getter or itself (chaining) if used as setter
6620    *
6621    * @kind function
6622    *
6623    * @description
6624    * Call this method to enable/disable various debug runtime information in the compiler such as adding
6625    * binding information and a reference to the current scope on to DOM elements.
6626    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
6627    * * `ng-binding` CSS class
6628    * * `$binding` data property containing an array of the binding expressions
6629    *
6630    * You may want to disable this in production for a significant performance boost. See
6631    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
6632    *
6633    * The default value is true.
6634    */
6635   var debugInfoEnabled = true;
6636   this.debugInfoEnabled = function(enabled) {
6637     if (isDefined(enabled)) {
6638       debugInfoEnabled = enabled;
6639       return this;
6640     }
6641     return debugInfoEnabled;
6642   };
6643
6644   this.$get = [
6645             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
6646             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
6647     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
6648              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
6649
6650     var Attributes = function(element, attributesToCopy) {
6651       if (attributesToCopy) {
6652         var keys = Object.keys(attributesToCopy);
6653         var i, l, key;
6654
6655         for (i = 0, l = keys.length; i < l; i++) {
6656           key = keys[i];
6657           this[key] = attributesToCopy[key];
6658         }
6659       } else {
6660         this.$attr = {};
6661       }
6662
6663       this.$$element = element;
6664     };
6665
6666     Attributes.prototype = {
6667       /**
6668        * @ngdoc method
6669        * @name $compile.directive.Attributes#$normalize
6670        * @kind function
6671        *
6672        * @description
6673        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
6674        * `data-`) to its normalized, camelCase form.
6675        *
6676        * Also there is special case for Moz prefix starting with upper case letter.
6677        *
6678        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
6679        *
6680        * @param {string} name Name to normalize
6681        */
6682       $normalize: directiveNormalize,
6683
6684
6685       /**
6686        * @ngdoc method
6687        * @name $compile.directive.Attributes#$addClass
6688        * @kind function
6689        *
6690        * @description
6691        * Adds the CSS class value specified by the classVal parameter to the element. If animations
6692        * are enabled then an animation will be triggered for the class addition.
6693        *
6694        * @param {string} classVal The className value that will be added to the element
6695        */
6696       $addClass: function(classVal) {
6697         if (classVal && classVal.length > 0) {
6698           $animate.addClass(this.$$element, classVal);
6699         }
6700       },
6701
6702       /**
6703        * @ngdoc method
6704        * @name $compile.directive.Attributes#$removeClass
6705        * @kind function
6706        *
6707        * @description
6708        * Removes the CSS class value specified by the classVal parameter from the element. If
6709        * animations are enabled then an animation will be triggered for the class removal.
6710        *
6711        * @param {string} classVal The className value that will be removed from the element
6712        */
6713       $removeClass: function(classVal) {
6714         if (classVal && classVal.length > 0) {
6715           $animate.removeClass(this.$$element, classVal);
6716         }
6717       },
6718
6719       /**
6720        * @ngdoc method
6721        * @name $compile.directive.Attributes#$updateClass
6722        * @kind function
6723        *
6724        * @description
6725        * Adds and removes the appropriate CSS class values to the element based on the difference
6726        * between the new and old CSS class values (specified as newClasses and oldClasses).
6727        *
6728        * @param {string} newClasses The current CSS className value
6729        * @param {string} oldClasses The former CSS className value
6730        */
6731       $updateClass: function(newClasses, oldClasses) {
6732         var toAdd = tokenDifference(newClasses, oldClasses);
6733         if (toAdd && toAdd.length) {
6734           $animate.addClass(this.$$element, toAdd);
6735         }
6736
6737         var toRemove = tokenDifference(oldClasses, newClasses);
6738         if (toRemove && toRemove.length) {
6739           $animate.removeClass(this.$$element, toRemove);
6740         }
6741       },
6742
6743       /**
6744        * Set a normalized attribute on the element in a way such that all directives
6745        * can share the attribute. This function properly handles boolean attributes.
6746        * @param {string} key Normalized key. (ie ngAttribute)
6747        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
6748        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
6749        *     Defaults to true.
6750        * @param {string=} attrName Optional none normalized name. Defaults to key.
6751        */
6752       $set: function(key, value, writeAttr, attrName) {
6753         // TODO: decide whether or not to throw an error if "class"
6754         //is set through this function since it may cause $updateClass to
6755         //become unstable.
6756
6757         var node = this.$$element[0],
6758             booleanKey = getBooleanAttrName(node, key),
6759             aliasedKey = getAliasedAttrName(node, key),
6760             observer = key,
6761             nodeName;
6762
6763         if (booleanKey) {
6764           this.$$element.prop(key, value);
6765           attrName = booleanKey;
6766         } else if (aliasedKey) {
6767           this[aliasedKey] = value;
6768           observer = aliasedKey;
6769         }
6770
6771         this[key] = value;
6772
6773         // translate normalized key to actual key
6774         if (attrName) {
6775           this.$attr[key] = attrName;
6776         } else {
6777           attrName = this.$attr[key];
6778           if (!attrName) {
6779             this.$attr[key] = attrName = snake_case(key, '-');
6780           }
6781         }
6782
6783         nodeName = nodeName_(this.$$element);
6784
6785         if ((nodeName === 'a' && key === 'href') ||
6786             (nodeName === 'img' && key === 'src')) {
6787           // sanitize a[href] and img[src] values
6788           this[key] = value = $$sanitizeUri(value, key === 'src');
6789         } else if (nodeName === 'img' && key === 'srcset') {
6790           // sanitize img[srcset] values
6791           var result = "";
6792
6793           // first check if there are spaces because it's not the same pattern
6794           var trimmedSrcset = trim(value);
6795           //                (   999x   ,|   999w   ,|   ,|,   )
6796           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
6797           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
6798
6799           // split srcset into tuple of uri and descriptor except for the last item
6800           var rawUris = trimmedSrcset.split(pattern);
6801
6802           // for each tuples
6803           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
6804           for (var i = 0; i < nbrUrisWith2parts; i++) {
6805             var innerIdx = i * 2;
6806             // sanitize the uri
6807             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
6808             // add the descriptor
6809             result += (" " + trim(rawUris[innerIdx + 1]));
6810           }
6811
6812           // split the last item into uri and descriptor
6813           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
6814
6815           // sanitize the last uri
6816           result += $$sanitizeUri(trim(lastTuple[0]), true);
6817
6818           // and add the last descriptor if any
6819           if (lastTuple.length === 2) {
6820             result += (" " + trim(lastTuple[1]));
6821           }
6822           this[key] = value = result;
6823         }
6824
6825         if (writeAttr !== false) {
6826           if (value === null || value === undefined) {
6827             this.$$element.removeAttr(attrName);
6828           } else {
6829             this.$$element.attr(attrName, value);
6830           }
6831         }
6832
6833         // fire observers
6834         var $$observers = this.$$observers;
6835         $$observers && forEach($$observers[observer], function(fn) {
6836           try {
6837             fn(value);
6838           } catch (e) {
6839             $exceptionHandler(e);
6840           }
6841         });
6842       },
6843
6844
6845       /**
6846        * @ngdoc method
6847        * @name $compile.directive.Attributes#$observe
6848        * @kind function
6849        *
6850        * @description
6851        * Observes an interpolated attribute.
6852        *
6853        * The observer function will be invoked once during the next `$digest` following
6854        * compilation. The observer is then invoked whenever the interpolated value
6855        * changes.
6856        *
6857        * @param {string} key Normalized key. (ie ngAttribute) .
6858        * @param {function(interpolatedValue)} fn Function that will be called whenever
6859                 the interpolated value of the attribute changes.
6860        *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
6861        * @returns {function()} Returns a deregistration function for this observer.
6862        */
6863       $observe: function(key, fn) {
6864         var attrs = this,
6865             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
6866             listeners = ($$observers[key] || ($$observers[key] = []));
6867
6868         listeners.push(fn);
6869         $rootScope.$evalAsync(function() {
6870           if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
6871             // no one registered attribute interpolation function, so lets call it manually
6872             fn(attrs[key]);
6873           }
6874         });
6875
6876         return function() {
6877           arrayRemove(listeners, fn);
6878         };
6879       }
6880     };
6881
6882
6883     function safeAddClass($element, className) {
6884       try {
6885         $element.addClass(className);
6886       } catch (e) {
6887         // ignore, since it means that we are trying to set class on
6888         // SVG element, where class name is read-only.
6889       }
6890     }
6891
6892
6893     var startSymbol = $interpolate.startSymbol(),
6894         endSymbol = $interpolate.endSymbol(),
6895         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
6896             ? identity
6897             : function denormalizeTemplate(template) {
6898               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
6899         },
6900         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
6901
6902     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
6903       var bindings = $element.data('$binding') || [];
6904
6905       if (isArray(binding)) {
6906         bindings = bindings.concat(binding);
6907       } else {
6908         bindings.push(binding);
6909       }
6910
6911       $element.data('$binding', bindings);
6912     } : noop;
6913
6914     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
6915       safeAddClass($element, 'ng-binding');
6916     } : noop;
6917
6918     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
6919       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
6920       $element.data(dataName, scope);
6921     } : noop;
6922
6923     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
6924       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
6925     } : noop;
6926
6927     return compile;
6928
6929     //================================
6930
6931     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
6932                         previousCompileContext) {
6933       if (!($compileNodes instanceof jqLite)) {
6934         // jquery always rewraps, whereas we need to preserve the original selector so that we can
6935         // modify it.
6936         $compileNodes = jqLite($compileNodes);
6937       }
6938       // We can not compile top level text elements since text nodes can be merged and we will
6939       // not be able to attach scope data to them, so we will wrap them in <span>
6940       forEach($compileNodes, function(node, index) {
6941         if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
6942           $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
6943         }
6944       });
6945       var compositeLinkFn =
6946               compileNodes($compileNodes, transcludeFn, $compileNodes,
6947                            maxPriority, ignoreDirective, previousCompileContext);
6948       compile.$$addScopeClass($compileNodes);
6949       var namespace = null;
6950       return function publicLinkFn(scope, cloneConnectFn, options) {
6951         assertArg(scope, 'scope');
6952
6953         options = options || {};
6954         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
6955           transcludeControllers = options.transcludeControllers,
6956           futureParentElement = options.futureParentElement;
6957
6958         // When `parentBoundTranscludeFn` is passed, it is a
6959         // `controllersBoundTransclude` function (it was previously passed
6960         // as `transclude` to directive.link) so we must unwrap it to get
6961         // its `boundTranscludeFn`
6962         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
6963           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
6964         }
6965
6966         if (!namespace) {
6967           namespace = detectNamespaceForChildElements(futureParentElement);
6968         }
6969         var $linkNode;
6970         if (namespace !== 'html') {
6971           // When using a directive with replace:true and templateUrl the $compileNodes
6972           // (or a child element inside of them)
6973           // might change, so we need to recreate the namespace adapted compileNodes
6974           // for call to the link function.
6975           // Note: This will already clone the nodes...
6976           $linkNode = jqLite(
6977             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
6978           );
6979         } else if (cloneConnectFn) {
6980           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
6981           // and sometimes changes the structure of the DOM.
6982           $linkNode = JQLitePrototype.clone.call($compileNodes);
6983         } else {
6984           $linkNode = $compileNodes;
6985         }
6986
6987         if (transcludeControllers) {
6988           for (var controllerName in transcludeControllers) {
6989             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
6990           }
6991         }
6992
6993         compile.$$addScopeInfo($linkNode, scope);
6994
6995         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
6996         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
6997         return $linkNode;
6998       };
6999     }
7000
7001     function detectNamespaceForChildElements(parentElement) {
7002       // TODO: Make this detect MathML as well...
7003       var node = parentElement && parentElement[0];
7004       if (!node) {
7005         return 'html';
7006       } else {
7007         return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7008       }
7009     }
7010
7011     /**
7012      * Compile function matches each node in nodeList against the directives. Once all directives
7013      * for a particular node are collected their compile functions are executed. The compile
7014      * functions return values - the linking functions - are combined into a composite linking
7015      * function, which is the a linking function for the node.
7016      *
7017      * @param {NodeList} nodeList an array of nodes or NodeList to compile
7018      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7019      *        scope argument is auto-generated to the new child of the transcluded parent scope.
7020      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7021      *        the rootElement must be set the jqLite collection of the compile root. This is
7022      *        needed so that the jqLite collection items can be replaced with widgets.
7023      * @param {number=} maxPriority Max directive priority.
7024      * @returns {Function} A composite linking function of all of the matched directives or null.
7025      */
7026     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7027                             previousCompileContext) {
7028       var linkFns = [],
7029           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7030
7031       for (var i = 0; i < nodeList.length; i++) {
7032         attrs = new Attributes();
7033
7034         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7035         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7036                                         ignoreDirective);
7037
7038         nodeLinkFn = (directives.length)
7039             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7040                                       null, [], [], previousCompileContext)
7041             : null;
7042
7043         if (nodeLinkFn && nodeLinkFn.scope) {
7044           compile.$$addScopeClass(attrs.$$element);
7045         }
7046
7047         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7048                       !(childNodes = nodeList[i].childNodes) ||
7049                       !childNodes.length)
7050             ? null
7051             : compileNodes(childNodes,
7052                  nodeLinkFn ? (
7053                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7054                      && nodeLinkFn.transclude) : transcludeFn);
7055
7056         if (nodeLinkFn || childLinkFn) {
7057           linkFns.push(i, nodeLinkFn, childLinkFn);
7058           linkFnFound = true;
7059           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7060         }
7061
7062         //use the previous context only for the first element in the virtual group
7063         previousCompileContext = null;
7064       }
7065
7066       // return a linking function if we have found anything, null otherwise
7067       return linkFnFound ? compositeLinkFn : null;
7068
7069       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7070         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7071         var stableNodeList;
7072
7073
7074         if (nodeLinkFnFound) {
7075           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7076           // offsets don't get screwed up
7077           var nodeListLength = nodeList.length;
7078           stableNodeList = new Array(nodeListLength);
7079
7080           // create a sparse array by only copying the elements which have a linkFn
7081           for (i = 0; i < linkFns.length; i+=3) {
7082             idx = linkFns[i];
7083             stableNodeList[idx] = nodeList[idx];
7084           }
7085         } else {
7086           stableNodeList = nodeList;
7087         }
7088
7089         for (i = 0, ii = linkFns.length; i < ii;) {
7090           node = stableNodeList[linkFns[i++]];
7091           nodeLinkFn = linkFns[i++];
7092           childLinkFn = linkFns[i++];
7093
7094           if (nodeLinkFn) {
7095             if (nodeLinkFn.scope) {
7096               childScope = scope.$new();
7097               compile.$$addScopeInfo(jqLite(node), childScope);
7098             } else {
7099               childScope = scope;
7100             }
7101
7102             if (nodeLinkFn.transcludeOnThisElement) {
7103               childBoundTranscludeFn = createBoundTranscludeFn(
7104                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
7105                   nodeLinkFn.elementTranscludeOnThisElement);
7106
7107             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7108               childBoundTranscludeFn = parentBoundTranscludeFn;
7109
7110             } else if (!parentBoundTranscludeFn && transcludeFn) {
7111               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7112
7113             } else {
7114               childBoundTranscludeFn = null;
7115             }
7116
7117             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7118
7119           } else if (childLinkFn) {
7120             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7121           }
7122         }
7123       }
7124     }
7125
7126     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
7127
7128       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7129
7130         if (!transcludedScope) {
7131           transcludedScope = scope.$new(false, containingScope);
7132           transcludedScope.$$transcluded = true;
7133         }
7134
7135         return transcludeFn(transcludedScope, cloneFn, {
7136           parentBoundTranscludeFn: previousBoundTranscludeFn,
7137           transcludeControllers: controllers,
7138           futureParentElement: futureParentElement
7139         });
7140       };
7141
7142       return boundTranscludeFn;
7143     }
7144
7145     /**
7146      * Looks for directives on the given node and adds them to the directive collection which is
7147      * sorted.
7148      *
7149      * @param node Node to search.
7150      * @param directives An array to which the directives are added to. This array is sorted before
7151      *        the function returns.
7152      * @param attrs The shared attrs object which is used to populate the normalized attributes.
7153      * @param {number=} maxPriority Max directive priority.
7154      */
7155     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7156       var nodeType = node.nodeType,
7157           attrsMap = attrs.$attr,
7158           match,
7159           className;
7160
7161       switch (nodeType) {
7162         case NODE_TYPE_ELEMENT: /* Element */
7163           // use the node name: <directive>
7164           addDirective(directives,
7165               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7166
7167           // iterate over the attributes
7168           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7169                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7170             var attrStartName = false;
7171             var attrEndName = false;
7172
7173             attr = nAttrs[j];
7174             name = attr.name;
7175             value = trim(attr.value);
7176
7177             // support ngAttr attribute binding
7178             ngAttrName = directiveNormalize(name);
7179             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7180               name = name.replace(PREFIX_REGEXP, '')
7181                 .substr(8).replace(/_(.)/g, function(match, letter) {
7182                   return letter.toUpperCase();
7183                 });
7184             }
7185
7186             var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
7187             if (directiveIsMultiElement(directiveNName)) {
7188               if (ngAttrName === directiveNName + 'Start') {
7189                 attrStartName = name;
7190                 attrEndName = name.substr(0, name.length - 5) + 'end';
7191                 name = name.substr(0, name.length - 6);
7192               }
7193             }
7194
7195             nName = directiveNormalize(name.toLowerCase());
7196             attrsMap[nName] = name;
7197             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7198                 attrs[nName] = value;
7199                 if (getBooleanAttrName(node, nName)) {
7200                   attrs[nName] = true; // presence means true
7201                 }
7202             }
7203             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7204             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7205                           attrEndName);
7206           }
7207
7208           // use class as directive
7209           className = node.className;
7210           if (isObject(className)) {
7211               // Maybe SVGAnimatedString
7212               className = className.animVal;
7213           }
7214           if (isString(className) && className !== '') {
7215             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7216               nName = directiveNormalize(match[2]);
7217               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7218                 attrs[nName] = trim(match[3]);
7219               }
7220               className = className.substr(match.index + match[0].length);
7221             }
7222           }
7223           break;
7224         case NODE_TYPE_TEXT: /* Text Node */
7225           addTextInterpolateDirective(directives, node.nodeValue);
7226           break;
7227         case NODE_TYPE_COMMENT: /* Comment */
7228           try {
7229             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7230             if (match) {
7231               nName = directiveNormalize(match[1]);
7232               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7233                 attrs[nName] = trim(match[2]);
7234               }
7235             }
7236           } catch (e) {
7237             // turns out that under some circumstances IE9 throws errors when one attempts to read
7238             // comment's node value.
7239             // Just ignore it and continue. (Can't seem to reproduce in test case.)
7240           }
7241           break;
7242       }
7243
7244       directives.sort(byPriority);
7245       return directives;
7246     }
7247
7248     /**
7249      * Given a node with an directive-start it collects all of the siblings until it finds
7250      * directive-end.
7251      * @param node
7252      * @param attrStart
7253      * @param attrEnd
7254      * @returns {*}
7255      */
7256     function groupScan(node, attrStart, attrEnd) {
7257       var nodes = [];
7258       var depth = 0;
7259       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7260         do {
7261           if (!node) {
7262             throw $compileMinErr('uterdir',
7263                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7264                       attrStart, attrEnd);
7265           }
7266           if (node.nodeType == NODE_TYPE_ELEMENT) {
7267             if (node.hasAttribute(attrStart)) depth++;
7268             if (node.hasAttribute(attrEnd)) depth--;
7269           }
7270           nodes.push(node);
7271           node = node.nextSibling;
7272         } while (depth > 0);
7273       } else {
7274         nodes.push(node);
7275       }
7276
7277       return jqLite(nodes);
7278     }
7279
7280     /**
7281      * Wrapper for linking function which converts normal linking function into a grouped
7282      * linking function.
7283      * @param linkFn
7284      * @param attrStart
7285      * @param attrEnd
7286      * @returns {Function}
7287      */
7288     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7289       return function(scope, element, attrs, controllers, transcludeFn) {
7290         element = groupScan(element[0], attrStart, attrEnd);
7291         return linkFn(scope, element, attrs, controllers, transcludeFn);
7292       };
7293     }
7294
7295     /**
7296      * Once the directives have been collected, their compile functions are executed. This method
7297      * is responsible for inlining directive templates as well as terminating the application
7298      * of the directives if the terminal directive has been reached.
7299      *
7300      * @param {Array} directives Array of collected directives to execute their compile function.
7301      *        this needs to be pre-sorted by priority order.
7302      * @param {Node} compileNode The raw DOM node to apply the compile functions to
7303      * @param {Object} templateAttrs The shared attribute function
7304      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7305      *                                                  scope argument is auto-generated to the new
7306      *                                                  child of the transcluded parent scope.
7307      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
7308      *                              argument has the root jqLite array so that we can replace nodes
7309      *                              on it.
7310      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
7311      *                                           compiling the transclusion.
7312      * @param {Array.<Function>} preLinkFns
7313      * @param {Array.<Function>} postLinkFns
7314      * @param {Object} previousCompileContext Context used for previous compilation of the current
7315      *                                        node
7316      * @returns {Function} linkFn
7317      */
7318     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
7319                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
7320                                    previousCompileContext) {
7321       previousCompileContext = previousCompileContext || {};
7322
7323       var terminalPriority = -Number.MAX_VALUE,
7324           newScopeDirective,
7325           controllerDirectives = previousCompileContext.controllerDirectives,
7326           controllers,
7327           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
7328           templateDirective = previousCompileContext.templateDirective,
7329           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
7330           hasTranscludeDirective = false,
7331           hasTemplate = false,
7332           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
7333           $compileNode = templateAttrs.$$element = jqLite(compileNode),
7334           directive,
7335           directiveName,
7336           $template,
7337           replaceDirective = originalReplaceDirective,
7338           childTranscludeFn = transcludeFn,
7339           linkFn,
7340           directiveValue;
7341
7342       // executes all directives on the current element
7343       for (var i = 0, ii = directives.length; i < ii; i++) {
7344         directive = directives[i];
7345         var attrStart = directive.$$start;
7346         var attrEnd = directive.$$end;
7347
7348         // collect multiblock sections
7349         if (attrStart) {
7350           $compileNode = groupScan(compileNode, attrStart, attrEnd);
7351         }
7352         $template = undefined;
7353
7354         if (terminalPriority > directive.priority) {
7355           break; // prevent further processing of directives
7356         }
7357
7358         if (directiveValue = directive.scope) {
7359
7360           // skip the check for directives with async templates, we'll check the derived sync
7361           // directive when the template arrives
7362           if (!directive.templateUrl) {
7363             if (isObject(directiveValue)) {
7364               // This directive is trying to add an isolated scope.
7365               // Check that there is no scope of any kind already
7366               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
7367                                 directive, $compileNode);
7368               newIsolateScopeDirective = directive;
7369             } else {
7370               // This directive is trying to add a child scope.
7371               // Check that there is no isolated scope already
7372               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
7373                                 $compileNode);
7374             }
7375           }
7376
7377           newScopeDirective = newScopeDirective || directive;
7378         }
7379
7380         directiveName = directive.name;
7381
7382         if (!directive.templateUrl && directive.controller) {
7383           directiveValue = directive.controller;
7384           controllerDirectives = controllerDirectives || {};
7385           assertNoDuplicate("'" + directiveName + "' controller",
7386               controllerDirectives[directiveName], directive, $compileNode);
7387           controllerDirectives[directiveName] = directive;
7388         }
7389
7390         if (directiveValue = directive.transclude) {
7391           hasTranscludeDirective = true;
7392
7393           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
7394           // This option should only be used by directives that know how to safely handle element transclusion,
7395           // where the transcluded nodes are added or replaced after linking.
7396           if (!directive.$$tlb) {
7397             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
7398             nonTlbTranscludeDirective = directive;
7399           }
7400
7401           if (directiveValue == 'element') {
7402             hasElementTranscludeDirective = true;
7403             terminalPriority = directive.priority;
7404             $template = $compileNode;
7405             $compileNode = templateAttrs.$$element =
7406                 jqLite(document.createComment(' ' + directiveName + ': ' +
7407                                               templateAttrs[directiveName] + ' '));
7408             compileNode = $compileNode[0];
7409             replaceWith(jqCollection, sliceArgs($template), compileNode);
7410
7411             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
7412                                         replaceDirective && replaceDirective.name, {
7413                                           // Don't pass in:
7414                                           // - controllerDirectives - otherwise we'll create duplicates controllers
7415                                           // - newIsolateScopeDirective or templateDirective - combining templates with
7416                                           //   element transclusion doesn't make sense.
7417                                           //
7418                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
7419                                           // on the same element more than once.
7420                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
7421                                         });
7422           } else {
7423             $template = jqLite(jqLiteClone(compileNode)).contents();
7424             $compileNode.empty(); // clear contents
7425             childTranscludeFn = compile($template, transcludeFn);
7426           }
7427         }
7428
7429         if (directive.template) {
7430           hasTemplate = true;
7431           assertNoDuplicate('template', templateDirective, directive, $compileNode);
7432           templateDirective = directive;
7433
7434           directiveValue = (isFunction(directive.template))
7435               ? directive.template($compileNode, templateAttrs)
7436               : directive.template;
7437
7438           directiveValue = denormalizeTemplate(directiveValue);
7439
7440           if (directive.replace) {
7441             replaceDirective = directive;
7442             if (jqLiteIsTextNode(directiveValue)) {
7443               $template = [];
7444             } else {
7445               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
7446             }
7447             compileNode = $template[0];
7448
7449             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7450               throw $compileMinErr('tplrt',
7451                   "Template for directive '{0}' must have exactly one root element. {1}",
7452                   directiveName, '');
7453             }
7454
7455             replaceWith(jqCollection, $compileNode, compileNode);
7456
7457             var newTemplateAttrs = {$attr: {}};
7458
7459             // combine directives from the original node and from the template:
7460             // - take the array of directives for this element
7461             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
7462             // - collect directives from the template and sort them by priority
7463             // - combine directives as: processed + template + unprocessed
7464             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
7465             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
7466
7467             if (newIsolateScopeDirective) {
7468               markDirectivesAsIsolate(templateDirectives);
7469             }
7470             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
7471             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
7472
7473             ii = directives.length;
7474           } else {
7475             $compileNode.html(directiveValue);
7476           }
7477         }
7478
7479         if (directive.templateUrl) {
7480           hasTemplate = true;
7481           assertNoDuplicate('template', templateDirective, directive, $compileNode);
7482           templateDirective = directive;
7483
7484           if (directive.replace) {
7485             replaceDirective = directive;
7486           }
7487
7488           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
7489               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
7490                 controllerDirectives: controllerDirectives,
7491                 newIsolateScopeDirective: newIsolateScopeDirective,
7492                 templateDirective: templateDirective,
7493                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
7494               });
7495           ii = directives.length;
7496         } else if (directive.compile) {
7497           try {
7498             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
7499             if (isFunction(linkFn)) {
7500               addLinkFns(null, linkFn, attrStart, attrEnd);
7501             } else if (linkFn) {
7502               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
7503             }
7504           } catch (e) {
7505             $exceptionHandler(e, startingTag($compileNode));
7506           }
7507         }
7508
7509         if (directive.terminal) {
7510           nodeLinkFn.terminal = true;
7511           terminalPriority = Math.max(terminalPriority, directive.priority);
7512         }
7513
7514       }
7515
7516       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
7517       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
7518       nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
7519       nodeLinkFn.templateOnThisElement = hasTemplate;
7520       nodeLinkFn.transclude = childTranscludeFn;
7521
7522       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
7523
7524       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
7525       return nodeLinkFn;
7526
7527       ////////////////////
7528
7529       function addLinkFns(pre, post, attrStart, attrEnd) {
7530         if (pre) {
7531           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
7532           pre.require = directive.require;
7533           pre.directiveName = directiveName;
7534           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7535             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
7536           }
7537           preLinkFns.push(pre);
7538         }
7539         if (post) {
7540           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
7541           post.require = directive.require;
7542           post.directiveName = directiveName;
7543           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7544             post = cloneAndAnnotateFn(post, {isolateScope: true});
7545           }
7546           postLinkFns.push(post);
7547         }
7548       }
7549
7550
7551       function getControllers(directiveName, require, $element, elementControllers) {
7552         var value, retrievalMethod = 'data', optional = false;
7553         var $searchElement = $element;
7554         var match;
7555         if (isString(require)) {
7556           match = require.match(REQUIRE_PREFIX_REGEXP);
7557           require = require.substring(match[0].length);
7558
7559           if (match[3]) {
7560             if (match[1]) match[3] = null;
7561             else match[1] = match[3];
7562           }
7563           if (match[1] === '^') {
7564             retrievalMethod = 'inheritedData';
7565           } else if (match[1] === '^^') {
7566             retrievalMethod = 'inheritedData';
7567             $searchElement = $element.parent();
7568           }
7569           if (match[2] === '?') {
7570             optional = true;
7571           }
7572
7573           value = null;
7574
7575           if (elementControllers && retrievalMethod === 'data') {
7576             if (value = elementControllers[require]) {
7577               value = value.instance;
7578             }
7579           }
7580           value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
7581
7582           if (!value && !optional) {
7583             throw $compileMinErr('ctreq',
7584                 "Controller '{0}', required by directive '{1}', can't be found!",
7585                 require, directiveName);
7586           }
7587           return value || null;
7588         } else if (isArray(require)) {
7589           value = [];
7590           forEach(require, function(require) {
7591             value.push(getControllers(directiveName, require, $element, elementControllers));
7592           });
7593         }
7594         return value;
7595       }
7596
7597
7598       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
7599         var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
7600             attrs;
7601
7602         if (compileNode === linkNode) {
7603           attrs = templateAttrs;
7604           $element = templateAttrs.$$element;
7605         } else {
7606           $element = jqLite(linkNode);
7607           attrs = new Attributes($element, templateAttrs);
7608         }
7609
7610         if (newIsolateScopeDirective) {
7611           isolateScope = scope.$new(true);
7612         }
7613
7614         if (boundTranscludeFn) {
7615           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
7616           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
7617           transcludeFn = controllersBoundTransclude;
7618           transcludeFn.$$boundTransclude = boundTranscludeFn;
7619         }
7620
7621         if (controllerDirectives) {
7622           // TODO: merge `controllers` and `elementControllers` into single object.
7623           controllers = {};
7624           elementControllers = {};
7625           forEach(controllerDirectives, function(directive) {
7626             var locals = {
7627               $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
7628               $element: $element,
7629               $attrs: attrs,
7630               $transclude: transcludeFn
7631             }, controllerInstance;
7632
7633             controller = directive.controller;
7634             if (controller == '@') {
7635               controller = attrs[directive.name];
7636             }
7637
7638             controllerInstance = $controller(controller, locals, true, directive.controllerAs);
7639
7640             // For directives with element transclusion the element is a comment,
7641             // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
7642             // clean up (http://bugs.jquery.com/ticket/8335).
7643             // Instead, we save the controllers for the element in a local hash and attach to .data
7644             // later, once we have the actual element.
7645             elementControllers[directive.name] = controllerInstance;
7646             if (!hasElementTranscludeDirective) {
7647               $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
7648             }
7649
7650             controllers[directive.name] = controllerInstance;
7651           });
7652         }
7653
7654         if (newIsolateScopeDirective) {
7655           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
7656               templateDirective === newIsolateScopeDirective.$$originalDirective)));
7657           compile.$$addScopeClass($element, true);
7658
7659           var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name];
7660           var isolateBindingContext = isolateScope;
7661           if (isolateScopeController && isolateScopeController.identifier &&
7662               newIsolateScopeDirective.bindToController === true) {
7663             isolateBindingContext = isolateScopeController.instance;
7664           }
7665
7666           forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) {
7667             var attrName = definition.attrName,
7668                 optional = definition.optional,
7669                 mode = definition.mode, // @, =, or &
7670                 lastValue,
7671                 parentGet, parentSet, compare;
7672
7673             switch (mode) {
7674
7675               case '@':
7676                 attrs.$observe(attrName, function(value) {
7677                   isolateBindingContext[scopeName] = value;
7678                 });
7679                 attrs.$$observers[attrName].$$scope = scope;
7680                 if (attrs[attrName]) {
7681                   // If the attribute has been provided then we trigger an interpolation to ensure
7682                   // the value is there for use in the link fn
7683                   isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
7684                 }
7685                 break;
7686
7687               case '=':
7688                 if (optional && !attrs[attrName]) {
7689                   return;
7690                 }
7691                 parentGet = $parse(attrs[attrName]);
7692                 if (parentGet.literal) {
7693                   compare = equals;
7694                 } else {
7695                   compare = function(a, b) { return a === b || (a !== a && b !== b); };
7696                 }
7697                 parentSet = parentGet.assign || function() {
7698                   // reset the change, or we will throw this exception on every $digest
7699                   lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7700                   throw $compileMinErr('nonassign',
7701                       "Expression '{0}' used with directive '{1}' is non-assignable!",
7702                       attrs[attrName], newIsolateScopeDirective.name);
7703                 };
7704                 lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7705                 var parentValueWatch = function parentValueWatch(parentValue) {
7706                   if (!compare(parentValue, isolateBindingContext[scopeName])) {
7707                     // we are out of sync and need to copy
7708                     if (!compare(parentValue, lastValue)) {
7709                       // parent changed and it has precedence
7710                       isolateBindingContext[scopeName] = parentValue;
7711                     } else {
7712                       // if the parent can be assigned then do so
7713                       parentSet(scope, parentValue = isolateBindingContext[scopeName]);
7714                     }
7715                   }
7716                   return lastValue = parentValue;
7717                 };
7718                 parentValueWatch.$stateful = true;
7719                 var unwatch;
7720                 if (definition.collection) {
7721                   unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
7722                 } else {
7723                   unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
7724                 }
7725                 isolateScope.$on('$destroy', unwatch);
7726                 break;
7727
7728               case '&':
7729                 parentGet = $parse(attrs[attrName]);
7730                 isolateBindingContext[scopeName] = function(locals) {
7731                   return parentGet(scope, locals);
7732                 };
7733                 break;
7734             }
7735           });
7736         }
7737         if (controllers) {
7738           forEach(controllers, function(controller) {
7739             controller();
7740           });
7741           controllers = null;
7742         }
7743
7744         // PRELINKING
7745         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
7746           linkFn = preLinkFns[i];
7747           invokeLinkFn(linkFn,
7748               linkFn.isolateScope ? isolateScope : scope,
7749               $element,
7750               attrs,
7751               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7752               transcludeFn
7753           );
7754         }
7755
7756         // RECURSION
7757         // We only pass the isolate scope, if the isolate directive has a template,
7758         // otherwise the child elements do not belong to the isolate directive.
7759         var scopeToChild = scope;
7760         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
7761           scopeToChild = isolateScope;
7762         }
7763         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
7764
7765         // POSTLINKING
7766         for (i = postLinkFns.length - 1; i >= 0; i--) {
7767           linkFn = postLinkFns[i];
7768           invokeLinkFn(linkFn,
7769               linkFn.isolateScope ? isolateScope : scope,
7770               $element,
7771               attrs,
7772               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7773               transcludeFn
7774           );
7775         }
7776
7777         // This is the function that is injected as `$transclude`.
7778         // Note: all arguments are optional!
7779         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
7780           var transcludeControllers;
7781
7782           // No scope passed in:
7783           if (!isScope(scope)) {
7784             futureParentElement = cloneAttachFn;
7785             cloneAttachFn = scope;
7786             scope = undefined;
7787           }
7788
7789           if (hasElementTranscludeDirective) {
7790             transcludeControllers = elementControllers;
7791           }
7792           if (!futureParentElement) {
7793             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
7794           }
7795           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
7796         }
7797       }
7798     }
7799
7800     function markDirectivesAsIsolate(directives) {
7801       // mark all directives as needing isolate scope.
7802       for (var j = 0, jj = directives.length; j < jj; j++) {
7803         directives[j] = inherit(directives[j], {$$isolateScope: true});
7804       }
7805     }
7806
7807     /**
7808      * looks up the directive and decorates it with exception handling and proper parameters. We
7809      * call this the boundDirective.
7810      *
7811      * @param {string} name name of the directive to look up.
7812      * @param {string} location The directive must be found in specific format.
7813      *   String containing any of theses characters:
7814      *
7815      *   * `E`: element name
7816      *   * `A': attribute
7817      *   * `C`: class
7818      *   * `M`: comment
7819      * @returns {boolean} true if directive was added.
7820      */
7821     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
7822                           endAttrName) {
7823       if (name === ignoreDirective) return null;
7824       var match = null;
7825       if (hasDirectives.hasOwnProperty(name)) {
7826         for (var directive, directives = $injector.get(name + Suffix),
7827             i = 0, ii = directives.length; i < ii; i++) {
7828           try {
7829             directive = directives[i];
7830             if ((maxPriority === undefined || maxPriority > directive.priority) &&
7831                  directive.restrict.indexOf(location) != -1) {
7832               if (startAttrName) {
7833                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
7834               }
7835               tDirectives.push(directive);
7836               match = directive;
7837             }
7838           } catch (e) { $exceptionHandler(e); }
7839         }
7840       }
7841       return match;
7842     }
7843
7844
7845     /**
7846      * looks up the directive and returns true if it is a multi-element directive,
7847      * and therefore requires DOM nodes between -start and -end markers to be grouped
7848      * together.
7849      *
7850      * @param {string} name name of the directive to look up.
7851      * @returns true if directive was registered as multi-element.
7852      */
7853     function directiveIsMultiElement(name) {
7854       if (hasDirectives.hasOwnProperty(name)) {
7855         for (var directive, directives = $injector.get(name + Suffix),
7856             i = 0, ii = directives.length; i < ii; i++) {
7857           directive = directives[i];
7858           if (directive.multiElement) {
7859             return true;
7860           }
7861         }
7862       }
7863       return false;
7864     }
7865
7866     /**
7867      * When the element is replaced with HTML template then the new attributes
7868      * on the template need to be merged with the existing attributes in the DOM.
7869      * The desired effect is to have both of the attributes present.
7870      *
7871      * @param {object} dst destination attributes (original DOM)
7872      * @param {object} src source attributes (from the directive template)
7873      */
7874     function mergeTemplateAttributes(dst, src) {
7875       var srcAttr = src.$attr,
7876           dstAttr = dst.$attr,
7877           $element = dst.$$element;
7878
7879       // reapply the old attributes to the new element
7880       forEach(dst, function(value, key) {
7881         if (key.charAt(0) != '$') {
7882           if (src[key] && src[key] !== value) {
7883             value += (key === 'style' ? ';' : ' ') + src[key];
7884           }
7885           dst.$set(key, value, true, srcAttr[key]);
7886         }
7887       });
7888
7889       // copy the new attributes on the old attrs object
7890       forEach(src, function(value, key) {
7891         if (key == 'class') {
7892           safeAddClass($element, value);
7893           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
7894         } else if (key == 'style') {
7895           $element.attr('style', $element.attr('style') + ';' + value);
7896           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
7897           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
7898           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
7899           // have an attribute like "has-own-property" or "data-has-own-property", etc.
7900         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
7901           dst[key] = value;
7902           dstAttr[key] = srcAttr[key];
7903         }
7904       });
7905     }
7906
7907
7908     function compileTemplateUrl(directives, $compileNode, tAttrs,
7909         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
7910       var linkQueue = [],
7911           afterTemplateNodeLinkFn,
7912           afterTemplateChildLinkFn,
7913           beforeTemplateCompileNode = $compileNode[0],
7914           origAsyncDirective = directives.shift(),
7915           derivedSyncDirective = inherit(origAsyncDirective, {
7916             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
7917           }),
7918           templateUrl = (isFunction(origAsyncDirective.templateUrl))
7919               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
7920               : origAsyncDirective.templateUrl,
7921           templateNamespace = origAsyncDirective.templateNamespace;
7922
7923       $compileNode.empty();
7924
7925       $templateRequest($sce.getTrustedResourceUrl(templateUrl))
7926         .then(function(content) {
7927           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
7928
7929           content = denormalizeTemplate(content);
7930
7931           if (origAsyncDirective.replace) {
7932             if (jqLiteIsTextNode(content)) {
7933               $template = [];
7934             } else {
7935               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
7936             }
7937             compileNode = $template[0];
7938
7939             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7940               throw $compileMinErr('tplrt',
7941                   "Template for directive '{0}' must have exactly one root element. {1}",
7942                   origAsyncDirective.name, templateUrl);
7943             }
7944
7945             tempTemplateAttrs = {$attr: {}};
7946             replaceWith($rootElement, $compileNode, compileNode);
7947             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
7948
7949             if (isObject(origAsyncDirective.scope)) {
7950               markDirectivesAsIsolate(templateDirectives);
7951             }
7952             directives = templateDirectives.concat(directives);
7953             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
7954           } else {
7955             compileNode = beforeTemplateCompileNode;
7956             $compileNode.html(content);
7957           }
7958
7959           directives.unshift(derivedSyncDirective);
7960
7961           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
7962               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
7963               previousCompileContext);
7964           forEach($rootElement, function(node, i) {
7965             if (node == compileNode) {
7966               $rootElement[i] = $compileNode[0];
7967             }
7968           });
7969           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
7970
7971           while (linkQueue.length) {
7972             var scope = linkQueue.shift(),
7973                 beforeTemplateLinkNode = linkQueue.shift(),
7974                 linkRootElement = linkQueue.shift(),
7975                 boundTranscludeFn = linkQueue.shift(),
7976                 linkNode = $compileNode[0];
7977
7978             if (scope.$$destroyed) continue;
7979
7980             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
7981               var oldClasses = beforeTemplateLinkNode.className;
7982
7983               if (!(previousCompileContext.hasElementTranscludeDirective &&
7984                   origAsyncDirective.replace)) {
7985                 // it was cloned therefore we have to clone as well.
7986                 linkNode = jqLiteClone(compileNode);
7987               }
7988               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
7989
7990               // Copy in CSS classes from original node
7991               safeAddClass(jqLite(linkNode), oldClasses);
7992             }
7993             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
7994               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
7995             } else {
7996               childBoundTranscludeFn = boundTranscludeFn;
7997             }
7998             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
7999               childBoundTranscludeFn);
8000           }
8001           linkQueue = null;
8002         });
8003
8004       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8005         var childBoundTranscludeFn = boundTranscludeFn;
8006         if (scope.$$destroyed) return;
8007         if (linkQueue) {
8008           linkQueue.push(scope,
8009                          node,
8010                          rootElement,
8011                          childBoundTranscludeFn);
8012         } else {
8013           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8014             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8015           }
8016           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8017         }
8018       };
8019     }
8020
8021
8022     /**
8023      * Sorting function for bound directives.
8024      */
8025     function byPriority(a, b) {
8026       var diff = b.priority - a.priority;
8027       if (diff !== 0) return diff;
8028       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8029       return a.index - b.index;
8030     }
8031
8032
8033     function assertNoDuplicate(what, previousDirective, directive, element) {
8034       if (previousDirective) {
8035         throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
8036             previousDirective.name, directive.name, what, startingTag(element));
8037       }
8038     }
8039
8040
8041     function addTextInterpolateDirective(directives, text) {
8042       var interpolateFn = $interpolate(text, true);
8043       if (interpolateFn) {
8044         directives.push({
8045           priority: 0,
8046           compile: function textInterpolateCompileFn(templateNode) {
8047             var templateNodeParent = templateNode.parent(),
8048                 hasCompileParent = !!templateNodeParent.length;
8049
8050             // When transcluding a template that has bindings in the root
8051             // we don't have a parent and thus need to add the class during linking fn.
8052             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8053
8054             return function textInterpolateLinkFn(scope, node) {
8055               var parent = node.parent();
8056               if (!hasCompileParent) compile.$$addBindingClass(parent);
8057               compile.$$addBindingInfo(parent, interpolateFn.expressions);
8058               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8059                 node[0].nodeValue = value;
8060               });
8061             };
8062           }
8063         });
8064       }
8065     }
8066
8067
8068     function wrapTemplate(type, template) {
8069       type = lowercase(type || 'html');
8070       switch (type) {
8071       case 'svg':
8072       case 'math':
8073         var wrapper = document.createElement('div');
8074         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8075         return wrapper.childNodes[0].childNodes;
8076       default:
8077         return template;
8078       }
8079     }
8080
8081
8082     function getTrustedContext(node, attrNormalizedName) {
8083       if (attrNormalizedName == "srcdoc") {
8084         return $sce.HTML;
8085       }
8086       var tag = nodeName_(node);
8087       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8088       if (attrNormalizedName == "xlinkHref" ||
8089           (tag == "form" && attrNormalizedName == "action") ||
8090           (tag != "img" && (attrNormalizedName == "src" ||
8091                             attrNormalizedName == "ngSrc"))) {
8092         return $sce.RESOURCE_URL;
8093       }
8094     }
8095
8096
8097     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8098       var trustedContext = getTrustedContext(node, name);
8099       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8100
8101       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8102
8103       // no interpolation found -> ignore
8104       if (!interpolateFn) return;
8105
8106
8107       if (name === "multiple" && nodeName_(node) === "select") {
8108         throw $compileMinErr("selmulti",
8109             "Binding to the 'multiple' attribute is not supported. Element: {0}",
8110             startingTag(node));
8111       }
8112
8113       directives.push({
8114         priority: 100,
8115         compile: function() {
8116             return {
8117               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8118                 var $$observers = (attr.$$observers || (attr.$$observers = {}));
8119
8120                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8121                   throw $compileMinErr('nodomevents',
8122                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8123                           "ng- versions (such as ng-click instead of onclick) instead.");
8124                 }
8125
8126                 // If the attribute has changed since last $interpolate()ed
8127                 var newValue = attr[name];
8128                 if (newValue !== value) {
8129                   // we need to interpolate again since the attribute value has been updated
8130                   // (e.g. by another directive's compile function)
8131                   // ensure unset/empty values make interpolateFn falsy
8132                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8133                   value = newValue;
8134                 }
8135
8136                 // if attribute was updated so that there is no interpolation going on we don't want to
8137                 // register any observers
8138                 if (!interpolateFn) return;
8139
8140                 // initialize attr object so that it's ready in case we need the value for isolate
8141                 // scope initialization, otherwise the value would not be available from isolate
8142                 // directive's linking fn during linking phase
8143                 attr[name] = interpolateFn(scope);
8144
8145                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8146                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
8147                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8148                     //special case for class attribute addition + removal
8149                     //so that class changes can tap into the animation
8150                     //hooks provided by the $animate service. Be sure to
8151                     //skip animations when the first digest occurs (when
8152                     //both the new and the old values are the same) since
8153                     //the CSS classes are the non-interpolated values
8154                     if (name === 'class' && newValue != oldValue) {
8155                       attr.$updateClass(newValue, oldValue);
8156                     } else {
8157                       attr.$set(name, newValue);
8158                     }
8159                   });
8160               }
8161             };
8162           }
8163       });
8164     }
8165
8166
8167     /**
8168      * This is a special jqLite.replaceWith, which can replace items which
8169      * have no parents, provided that the containing jqLite collection is provided.
8170      *
8171      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8172      *                               in the root of the tree.
8173      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8174      *                                  the shell, but replace its DOM node reference.
8175      * @param {Node} newNode The new DOM node.
8176      */
8177     function replaceWith($rootElement, elementsToRemove, newNode) {
8178       var firstElementToRemove = elementsToRemove[0],
8179           removeCount = elementsToRemove.length,
8180           parent = firstElementToRemove.parentNode,
8181           i, ii;
8182
8183       if ($rootElement) {
8184         for (i = 0, ii = $rootElement.length; i < ii; i++) {
8185           if ($rootElement[i] == firstElementToRemove) {
8186             $rootElement[i++] = newNode;
8187             for (var j = i, j2 = j + removeCount - 1,
8188                      jj = $rootElement.length;
8189                  j < jj; j++, j2++) {
8190               if (j2 < jj) {
8191                 $rootElement[j] = $rootElement[j2];
8192               } else {
8193                 delete $rootElement[j];
8194               }
8195             }
8196             $rootElement.length -= removeCount - 1;
8197
8198             // If the replaced element is also the jQuery .context then replace it
8199             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8200             // http://api.jquery.com/context/
8201             if ($rootElement.context === firstElementToRemove) {
8202               $rootElement.context = newNode;
8203             }
8204             break;
8205           }
8206         }
8207       }
8208
8209       if (parent) {
8210         parent.replaceChild(newNode, firstElementToRemove);
8211       }
8212
8213       // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8214       var fragment = document.createDocumentFragment();
8215       fragment.appendChild(firstElementToRemove);
8216
8217       // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8218       // data here because there's no public interface in jQuery to do that and copying over
8219       // event listeners (which is the main use of private data) wouldn't work anyway.
8220       jqLite(newNode).data(jqLite(firstElementToRemove).data());
8221
8222       // Remove data of the replaced element. We cannot just call .remove()
8223       // on the element it since that would deallocate scope that is needed
8224       // for the new node. Instead, remove the data "manually".
8225       if (!jQuery) {
8226         delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8227       } else {
8228         // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8229         // the replaced element. The cleanData version monkey-patched by Angular would cause
8230         // the scope to be trashed and we do need the very same scope to work with the new
8231         // element. However, we cannot just cache the non-patched version and use it here as
8232         // that would break if another library patches the method after Angular does (one
8233         // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8234         // skipped this one time.
8235         skipDestroyOnNextJQueryCleanData = true;
8236         jQuery.cleanData([firstElementToRemove]);
8237       }
8238
8239       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8240         var element = elementsToRemove[k];
8241         jqLite(element).remove(); // must do this way to clean up expando
8242         fragment.appendChild(element);
8243         delete elementsToRemove[k];
8244       }
8245
8246       elementsToRemove[0] = newNode;
8247       elementsToRemove.length = 1;
8248     }
8249
8250
8251     function cloneAndAnnotateFn(fn, annotation) {
8252       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8253     }
8254
8255
8256     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8257       try {
8258         linkFn(scope, $element, attrs, controllers, transcludeFn);
8259       } catch (e) {
8260         $exceptionHandler(e, startingTag($element));
8261       }
8262     }
8263   }];
8264 }
8265
8266 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8267 /**
8268  * Converts all accepted directives format into proper directive name.
8269  * @param name Name to normalize
8270  */
8271 function directiveNormalize(name) {
8272   return camelCase(name.replace(PREFIX_REGEXP, ''));
8273 }
8274
8275 /**
8276  * @ngdoc type
8277  * @name $compile.directive.Attributes
8278  *
8279  * @description
8280  * A shared object between directive compile / linking functions which contains normalized DOM
8281  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
8282  * needed since all of these are treated as equivalent in Angular:
8283  *
8284  * ```
8285  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
8286  * ```
8287  */
8288
8289 /**
8290  * @ngdoc property
8291  * @name $compile.directive.Attributes#$attr
8292  *
8293  * @description
8294  * A map of DOM element attribute names to the normalized name. This is
8295  * needed to do reverse lookup from normalized name back to actual name.
8296  */
8297
8298
8299 /**
8300  * @ngdoc method
8301  * @name $compile.directive.Attributes#$set
8302  * @kind function
8303  *
8304  * @description
8305  * Set DOM element attribute value.
8306  *
8307  *
8308  * @param {string} name Normalized element attribute name of the property to modify. The name is
8309  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
8310  *          property to the original name.
8311  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
8312  */
8313
8314
8315
8316 /**
8317  * Closure compiler type information
8318  */
8319
8320 function nodesetLinkingFn(
8321   /* angular.Scope */ scope,
8322   /* NodeList */ nodeList,
8323   /* Element */ rootElement,
8324   /* function(Function) */ boundTranscludeFn
8325 ) {}
8326
8327 function directiveLinkingFn(
8328   /* nodesetLinkingFn */ nodesetLinkingFn,
8329   /* angular.Scope */ scope,
8330   /* Node */ node,
8331   /* Element */ rootElement,
8332   /* function(Function) */ boundTranscludeFn
8333 ) {}
8334
8335 function tokenDifference(str1, str2) {
8336   var values = '',
8337       tokens1 = str1.split(/\s+/),
8338       tokens2 = str2.split(/\s+/);
8339
8340   outer:
8341   for (var i = 0; i < tokens1.length; i++) {
8342     var token = tokens1[i];
8343     for (var j = 0; j < tokens2.length; j++) {
8344       if (token == tokens2[j]) continue outer;
8345     }
8346     values += (values.length > 0 ? ' ' : '') + token;
8347   }
8348   return values;
8349 }
8350
8351 function removeComments(jqNodes) {
8352   jqNodes = jqLite(jqNodes);
8353   var i = jqNodes.length;
8354
8355   if (i <= 1) {
8356     return jqNodes;
8357   }
8358
8359   while (i--) {
8360     var node = jqNodes[i];
8361     if (node.nodeType === NODE_TYPE_COMMENT) {
8362       splice.call(jqNodes, i, 1);
8363     }
8364   }
8365   return jqNodes;
8366 }
8367
8368 var $controllerMinErr = minErr('$controller');
8369
8370 /**
8371  * @ngdoc provider
8372  * @name $controllerProvider
8373  * @description
8374  * The {@link ng.$controller $controller service} is used by Angular to create new
8375  * controllers.
8376  *
8377  * This provider allows controller registration via the
8378  * {@link ng.$controllerProvider#register register} method.
8379  */
8380 function $ControllerProvider() {
8381   var controllers = {},
8382       globals = false,
8383       CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
8384
8385
8386   /**
8387    * @ngdoc method
8388    * @name $controllerProvider#register
8389    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
8390    *    the names and the values are the constructors.
8391    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
8392    *    annotations in the array notation).
8393    */
8394   this.register = function(name, constructor) {
8395     assertNotHasOwnProperty(name, 'controller');
8396     if (isObject(name)) {
8397       extend(controllers, name);
8398     } else {
8399       controllers[name] = constructor;
8400     }
8401   };
8402
8403   /**
8404    * @ngdoc method
8405    * @name $controllerProvider#allowGlobals
8406    * @description If called, allows `$controller` to find controller constructors on `window`
8407    */
8408   this.allowGlobals = function() {
8409     globals = true;
8410   };
8411
8412
8413   this.$get = ['$injector', '$window', function($injector, $window) {
8414
8415     /**
8416      * @ngdoc service
8417      * @name $controller
8418      * @requires $injector
8419      *
8420      * @param {Function|string} constructor If called with a function then it's considered to be the
8421      *    controller constructor function. Otherwise it's considered to be a string which is used
8422      *    to retrieve the controller constructor using the following steps:
8423      *
8424      *    * check if a controller with given name is registered via `$controllerProvider`
8425      *    * check if evaluating the string on the current scope returns a constructor
8426      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
8427      *      `window` object (not recommended)
8428      *
8429      *    The string can use the `controller as property` syntax, where the controller instance is published
8430      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
8431      *    to work correctly.
8432      *
8433      * @param {Object} locals Injection locals for Controller.
8434      * @return {Object} Instance of given controller.
8435      *
8436      * @description
8437      * `$controller` service is responsible for instantiating controllers.
8438      *
8439      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
8440      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
8441      */
8442     return function(expression, locals, later, ident) {
8443       // PRIVATE API:
8444       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
8445       //                     If true, $controller will allocate the object with the correct
8446       //                     prototype chain, but will not invoke the controller until a returned
8447       //                     callback is invoked.
8448       //   param `ident` --- An optional label which overrides the label parsed from the controller
8449       //                     expression, if any.
8450       var instance, match, constructor, identifier;
8451       later = later === true;
8452       if (ident && isString(ident)) {
8453         identifier = ident;
8454       }
8455
8456       if (isString(expression)) {
8457         match = expression.match(CNTRL_REG);
8458         if (!match) {
8459           throw $controllerMinErr('ctrlfmt',
8460             "Badly formed controller string '{0}'. " +
8461             "Must match `__name__ as __id__` or `__name__`.", expression);
8462         }
8463         constructor = match[1],
8464         identifier = identifier || match[3];
8465         expression = controllers.hasOwnProperty(constructor)
8466             ? controllers[constructor]
8467             : getter(locals.$scope, constructor, true) ||
8468                 (globals ? getter($window, constructor, true) : undefined);
8469
8470         assertArgFn(expression, constructor, true);
8471       }
8472
8473       if (later) {
8474         // Instantiate controller later:
8475         // This machinery is used to create an instance of the object before calling the
8476         // controller's constructor itself.
8477         //
8478         // This allows properties to be added to the controller before the constructor is
8479         // invoked. Primarily, this is used for isolate scope bindings in $compile.
8480         //
8481         // This feature is not intended for use by applications, and is thus not documented
8482         // publicly.
8483         // Object creation: http://jsperf.com/create-constructor/2
8484         var controllerPrototype = (isArray(expression) ?
8485           expression[expression.length - 1] : expression).prototype;
8486         instance = Object.create(controllerPrototype || null);
8487
8488         if (identifier) {
8489           addIdentifier(locals, identifier, instance, constructor || expression.name);
8490         }
8491
8492         return extend(function() {
8493           $injector.invoke(expression, instance, locals, constructor);
8494           return instance;
8495         }, {
8496           instance: instance,
8497           identifier: identifier
8498         });
8499       }
8500
8501       instance = $injector.instantiate(expression, locals, constructor);
8502
8503       if (identifier) {
8504         addIdentifier(locals, identifier, instance, constructor || expression.name);
8505       }
8506
8507       return instance;
8508     };
8509
8510     function addIdentifier(locals, identifier, instance, name) {
8511       if (!(locals && isObject(locals.$scope))) {
8512         throw minErr('$controller')('noscp',
8513           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
8514           name, identifier);
8515       }
8516
8517       locals.$scope[identifier] = instance;
8518     }
8519   }];
8520 }
8521
8522 /**
8523  * @ngdoc service
8524  * @name $document
8525  * @requires $window
8526  *
8527  * @description
8528  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
8529  *
8530  * @example
8531    <example module="documentExample">
8532      <file name="index.html">
8533        <div ng-controller="ExampleController">
8534          <p>$document title: <b ng-bind="title"></b></p>
8535          <p>window.document title: <b ng-bind="windowTitle"></b></p>
8536        </div>
8537      </file>
8538      <file name="script.js">
8539        angular.module('documentExample', [])
8540          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
8541            $scope.title = $document[0].title;
8542            $scope.windowTitle = angular.element(window.document)[0].title;
8543          }]);
8544      </file>
8545    </example>
8546  */
8547 function $DocumentProvider() {
8548   this.$get = ['$window', function(window) {
8549     return jqLite(window.document);
8550   }];
8551 }
8552
8553 /**
8554  * @ngdoc service
8555  * @name $exceptionHandler
8556  * @requires ng.$log
8557  *
8558  * @description
8559  * Any uncaught exception in angular expressions is delegated to this service.
8560  * The default implementation simply delegates to `$log.error` which logs it into
8561  * the browser console.
8562  *
8563  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
8564  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
8565  *
8566  * ## Example:
8567  *
8568  * ```js
8569  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
8570  *     return function(exception, cause) {
8571  *       exception.message += ' (caused by "' + cause + '")';
8572  *       throw exception;
8573  *     };
8574  *   });
8575  * ```
8576  *
8577  * This example will override the normal action of `$exceptionHandler`, to make angular
8578  * exceptions fail hard when they happen, instead of just logging to the console.
8579  *
8580  * <hr />
8581  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
8582  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
8583  * (unless executed during a digest).
8584  *
8585  * If you wish, you can manually delegate exceptions, e.g.
8586  * `try { ... } catch(e) { $exceptionHandler(e); }`
8587  *
8588  * @param {Error} exception Exception associated with the error.
8589  * @param {string=} cause optional information about the context in which
8590  *       the error was thrown.
8591  *
8592  */
8593 function $ExceptionHandlerProvider() {
8594   this.$get = ['$log', function($log) {
8595     return function(exception, cause) {
8596       $log.error.apply($log, arguments);
8597     };
8598   }];
8599 }
8600
8601 var APPLICATION_JSON = 'application/json';
8602 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
8603 var JSON_START = /^\[|^\{(?!\{)/;
8604 var JSON_ENDS = {
8605   '[': /]$/,
8606   '{': /}$/
8607 };
8608 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
8609
8610 function defaultHttpResponseTransform(data, headers) {
8611   if (isString(data)) {
8612     // Strip json vulnerability protection prefix and trim whitespace
8613     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
8614
8615     if (tempData) {
8616       var contentType = headers('Content-Type');
8617       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
8618         data = fromJson(tempData);
8619       }
8620     }
8621   }
8622
8623   return data;
8624 }
8625
8626 function isJsonLike(str) {
8627     var jsonStart = str.match(JSON_START);
8628     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
8629 }
8630
8631 /**
8632  * Parse headers into key value object
8633  *
8634  * @param {string} headers Raw headers as a string
8635  * @returns {Object} Parsed headers as key value object
8636  */
8637 function parseHeaders(headers) {
8638   var parsed = createMap(), key, val, i;
8639
8640   if (!headers) return parsed;
8641
8642   forEach(headers.split('\n'), function(line) {
8643     i = line.indexOf(':');
8644     key = lowercase(trim(line.substr(0, i)));
8645     val = trim(line.substr(i + 1));
8646
8647     if (key) {
8648       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
8649     }
8650   });
8651
8652   return parsed;
8653 }
8654
8655
8656 /**
8657  * Returns a function that provides access to parsed headers.
8658  *
8659  * Headers are lazy parsed when first requested.
8660  * @see parseHeaders
8661  *
8662  * @param {(string|Object)} headers Headers to provide access to.
8663  * @returns {function(string=)} Returns a getter function which if called with:
8664  *
8665  *   - if called with single an argument returns a single header value or null
8666  *   - if called with no arguments returns an object containing all headers.
8667  */
8668 function headersGetter(headers) {
8669   var headersObj = isObject(headers) ? headers : undefined;
8670
8671   return function(name) {
8672     if (!headersObj) headersObj =  parseHeaders(headers);
8673
8674     if (name) {
8675       var value = headersObj[lowercase(name)];
8676       if (value === void 0) {
8677         value = null;
8678       }
8679       return value;
8680     }
8681
8682     return headersObj;
8683   };
8684 }
8685
8686
8687 /**
8688  * Chain all given functions
8689  *
8690  * This function is used for both request and response transforming
8691  *
8692  * @param {*} data Data to transform.
8693  * @param {function(string=)} headers HTTP headers getter fn.
8694  * @param {number} status HTTP status code of the response.
8695  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
8696  * @returns {*} Transformed data.
8697  */
8698 function transformData(data, headers, status, fns) {
8699   if (isFunction(fns))
8700     return fns(data, headers, status);
8701
8702   forEach(fns, function(fn) {
8703     data = fn(data, headers, status);
8704   });
8705
8706   return data;
8707 }
8708
8709
8710 function isSuccess(status) {
8711   return 200 <= status && status < 300;
8712 }
8713
8714
8715 /**
8716  * @ngdoc provider
8717  * @name $httpProvider
8718  * @description
8719  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
8720  * */
8721 function $HttpProvider() {
8722   /**
8723    * @ngdoc property
8724    * @name $httpProvider#defaults
8725    * @description
8726    *
8727    * Object containing default values for all {@link ng.$http $http} requests.
8728    *
8729    * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
8730    * that will provide the cache for all requests who set their `cache` property to `true`.
8731    * If you set the `default.cache = false` then only requests that specify their own custom
8732    * cache object will be cached. See {@link $http#caching $http Caching} for more information.
8733    *
8734    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
8735    * Defaults value is `'XSRF-TOKEN'`.
8736    *
8737    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
8738    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
8739    *
8740    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
8741    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
8742    * setting default headers.
8743    *     - **`defaults.headers.common`**
8744    *     - **`defaults.headers.post`**
8745    *     - **`defaults.headers.put`**
8746    *     - **`defaults.headers.patch`**
8747    *
8748    **/
8749   var defaults = this.defaults = {
8750     // transform incoming response data
8751     transformResponse: [defaultHttpResponseTransform],
8752
8753     // transform outgoing request data
8754     transformRequest: [function(d) {
8755       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
8756     }],
8757
8758     // default headers
8759     headers: {
8760       common: {
8761         'Accept': 'application/json, text/plain, */*'
8762       },
8763       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8764       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8765       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
8766     },
8767
8768     xsrfCookieName: 'XSRF-TOKEN',
8769     xsrfHeaderName: 'X-XSRF-TOKEN'
8770   };
8771
8772   var useApplyAsync = false;
8773   /**
8774    * @ngdoc method
8775    * @name $httpProvider#useApplyAsync
8776    * @description
8777    *
8778    * Configure $http service to combine processing of multiple http responses received at around
8779    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
8780    * significant performance improvement for bigger applications that make many HTTP requests
8781    * concurrently (common during application bootstrap).
8782    *
8783    * Defaults to false. If no value is specifed, returns the current configured value.
8784    *
8785    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
8786    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
8787    *    to load and share the same digest cycle.
8788    *
8789    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
8790    *    otherwise, returns the current configured value.
8791    **/
8792   this.useApplyAsync = function(value) {
8793     if (isDefined(value)) {
8794       useApplyAsync = !!value;
8795       return this;
8796     }
8797     return useApplyAsync;
8798   };
8799
8800   /**
8801    * @ngdoc property
8802    * @name $httpProvider#interceptors
8803    * @description
8804    *
8805    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
8806    * pre-processing of request or postprocessing of responses.
8807    *
8808    * These service factories are ordered by request, i.e. they are applied in the same order as the
8809    * array, on request, but reverse order, on response.
8810    *
8811    * {@link ng.$http#interceptors Interceptors detailed info}
8812    **/
8813   var interceptorFactories = this.interceptors = [];
8814
8815   this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
8816       function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
8817
8818     var defaultCache = $cacheFactory('$http');
8819
8820     /**
8821      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
8822      * The reversal is needed so that we can build up the interception chain around the
8823      * server request.
8824      */
8825     var reversedInterceptors = [];
8826
8827     forEach(interceptorFactories, function(interceptorFactory) {
8828       reversedInterceptors.unshift(isString(interceptorFactory)
8829           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
8830     });
8831
8832     /**
8833      * @ngdoc service
8834      * @kind function
8835      * @name $http
8836      * @requires ng.$httpBackend
8837      * @requires $cacheFactory
8838      * @requires $rootScope
8839      * @requires $q
8840      * @requires $injector
8841      *
8842      * @description
8843      * The `$http` service is a core Angular service that facilitates communication with the remote
8844      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
8845      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
8846      *
8847      * For unit testing applications that use `$http` service, see
8848      * {@link ngMock.$httpBackend $httpBackend mock}.
8849      *
8850      * For a higher level of abstraction, please check out the {@link ngResource.$resource
8851      * $resource} service.
8852      *
8853      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
8854      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
8855      * it is important to familiarize yourself with these APIs and the guarantees they provide.
8856      *
8857      *
8858      * ## General usage
8859      * The `$http` service is a function which takes a single argument — a configuration object —
8860      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
8861      * with two $http specific methods: `success` and `error`.
8862      *
8863      * ```js
8864      *   // Simple GET request example :
8865      *   $http.get('/someUrl').
8866      *     success(function(data, status, headers, config) {
8867      *       // this callback will be called asynchronously
8868      *       // when the response is available
8869      *     }).
8870      *     error(function(data, status, headers, config) {
8871      *       // called asynchronously if an error occurs
8872      *       // or server returns response with an error status.
8873      *     });
8874      * ```
8875      *
8876      * ```js
8877      *   // Simple POST request example (passing data) :
8878      *   $http.post('/someUrl', {msg:'hello word!'}).
8879      *     success(function(data, status, headers, config) {
8880      *       // this callback will be called asynchronously
8881      *       // when the response is available
8882      *     }).
8883      *     error(function(data, status, headers, config) {
8884      *       // called asynchronously if an error occurs
8885      *       // or server returns response with an error status.
8886      *     });
8887      * ```
8888      *
8889      *
8890      * Since the returned value of calling the $http function is a `promise`, you can also use
8891      * the `then` method to register callbacks, and these callbacks will receive a single argument –
8892      * an object representing the response. See the API signature and type info below for more
8893      * details.
8894      *
8895      * A response status code between 200 and 299 is considered a success status and
8896      * will result in the success callback being called. Note that if the response is a redirect,
8897      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
8898      * called for such responses.
8899      *
8900      * ## Writing Unit Tests that use $http
8901      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
8902      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
8903      * request using trained responses.
8904      *
8905      * ```
8906      * $httpBackend.expectGET(...);
8907      * $http.get(...);
8908      * $httpBackend.flush();
8909      * ```
8910      *
8911      * ## Shortcut methods
8912      *
8913      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
8914      * request data must be passed in for POST/PUT requests.
8915      *
8916      * ```js
8917      *   $http.get('/someUrl').success(successCallback);
8918      *   $http.post('/someUrl', data).success(successCallback);
8919      * ```
8920      *
8921      * Complete list of shortcut methods:
8922      *
8923      * - {@link ng.$http#get $http.get}
8924      * - {@link ng.$http#head $http.head}
8925      * - {@link ng.$http#post $http.post}
8926      * - {@link ng.$http#put $http.put}
8927      * - {@link ng.$http#delete $http.delete}
8928      * - {@link ng.$http#jsonp $http.jsonp}
8929      * - {@link ng.$http#patch $http.patch}
8930      *
8931      *
8932      * ## Setting HTTP Headers
8933      *
8934      * The $http service will automatically add certain HTTP headers to all requests. These defaults
8935      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
8936      * object, which currently contains this default configuration:
8937      *
8938      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
8939      *   - `Accept: application/json, text/plain, * / *`
8940      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
8941      *   - `Content-Type: application/json`
8942      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
8943      *   - `Content-Type: application/json`
8944      *
8945      * To add or overwrite these defaults, simply add or remove a property from these configuration
8946      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
8947      * with the lowercased HTTP method name as the key, e.g.
8948      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
8949      *
8950      * The defaults can also be set at runtime via the `$http.defaults` object in the same
8951      * fashion. For example:
8952      *
8953      * ```
8954      * module.run(function($http) {
8955      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
8956      * });
8957      * ```
8958      *
8959      * In addition, you can supply a `headers` property in the config object passed when
8960      * calling `$http(config)`, which overrides the defaults without changing them globally.
8961      *
8962      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
8963      * Use the `headers` property, setting the desired header to `undefined`. For example:
8964      *
8965      * ```js
8966      * var req = {
8967      *  method: 'POST',
8968      *  url: 'http://example.com',
8969      *  headers: {
8970      *    'Content-Type': undefined
8971      *  },
8972      *  data: { test: 'test' },
8973      * }
8974      *
8975      * $http(req).success(function(){...}).error(function(){...});
8976      * ```
8977      *
8978      * ## Transforming Requests and Responses
8979      *
8980      * Both requests and responses can be transformed using transformation functions: `transformRequest`
8981      * and `transformResponse`. These properties can be a single function that returns
8982      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
8983      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
8984      *
8985      * ### Default Transformations
8986      *
8987      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
8988      * `defaults.transformResponse` properties. If a request does not provide its own transformations
8989      * then these will be applied.
8990      *
8991      * You can augment or replace the default transformations by modifying these properties by adding to or
8992      * replacing the array.
8993      *
8994      * Angular provides the following default transformations:
8995      *
8996      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
8997      *
8998      * - If the `data` property of the request configuration object contains an object, serialize it
8999      *   into JSON format.
9000      *
9001      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9002      *
9003      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9004      *  - If JSON response is detected, deserialize it using a JSON parser.
9005      *
9006      *
9007      * ### Overriding the Default Transformations Per Request
9008      *
9009      * If you wish override the request/response transformations only for a single request then provide
9010      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9011      * into `$http`.
9012      *
9013      * Note that if you provide these properties on the config object the default transformations will be
9014      * overwritten. If you wish to augment the default transformations then you must include them in your
9015      * local transformation array.
9016      *
9017      * The following code demonstrates adding a new response transformation to be run after the default response
9018      * transformations have been run.
9019      *
9020      * ```js
9021      * function appendTransform(defaults, transform) {
9022      *
9023      *   // We can't guarantee that the default transformation is an array
9024      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9025      *
9026      *   // Append the new transformation to the defaults
9027      *   return defaults.concat(transform);
9028      * }
9029      *
9030      * $http({
9031      *   url: '...',
9032      *   method: 'GET',
9033      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9034      *     return doTransform(value);
9035      *   })
9036      * });
9037      * ```
9038      *
9039      *
9040      * ## Caching
9041      *
9042      * To enable caching, set the request configuration `cache` property to `true` (to use default
9043      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
9044      * When the cache is enabled, `$http` stores the response from the server in the specified
9045      * cache. The next time the same request is made, the response is served from the cache without
9046      * sending a request to the server.
9047      *
9048      * Note that even if the response is served from cache, delivery of the data is asynchronous in
9049      * the same way that real requests are.
9050      *
9051      * If there are multiple GET requests for the same URL that should be cached using the same
9052      * cache, but the cache is not populated yet, only one request to the server will be made and
9053      * the remaining requests will be fulfilled using the response from the first request.
9054      *
9055      * You can change the default cache to a new object (built with
9056      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
9057      * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
9058      * their `cache` property to `true` will now use this cache object.
9059      *
9060      * If you set the default cache to `false` then only requests that specify their own custom
9061      * cache object will be cached.
9062      *
9063      * ## Interceptors
9064      *
9065      * Before you start creating interceptors, be sure to understand the
9066      * {@link ng.$q $q and deferred/promise APIs}.
9067      *
9068      * For purposes of global error handling, authentication, or any kind of synchronous or
9069      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
9070      * able to intercept requests before they are handed to the server and
9071      * responses before they are handed over to the application code that
9072      * initiated these requests. The interceptors leverage the {@link ng.$q
9073      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
9074      *
9075      * The interceptors are service factories that are registered with the `$httpProvider` by
9076      * adding them to the `$httpProvider.interceptors` array. The factory is called and
9077      * injected with dependencies (if specified) and returns the interceptor.
9078      *
9079      * There are two kinds of interceptors (and two kinds of rejection interceptors):
9080      *
9081      *   * `request`: interceptors get called with a http `config` object. The function is free to
9082      *     modify the `config` object or create a new one. The function needs to return the `config`
9083      *     object directly, or a promise containing the `config` or a new `config` object.
9084      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
9085      *     resolved with a rejection.
9086      *   * `response`: interceptors get called with http `response` object. The function is free to
9087      *     modify the `response` object or create a new one. The function needs to return the `response`
9088      *     object directly, or as a promise containing the `response` or a new `response` object.
9089      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
9090      *     resolved with a rejection.
9091      *
9092      *
9093      * ```js
9094      *   // register the interceptor as a service
9095      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
9096      *     return {
9097      *       // optional method
9098      *       'request': function(config) {
9099      *         // do something on success
9100      *         return config;
9101      *       },
9102      *
9103      *       // optional method
9104      *      'requestError': function(rejection) {
9105      *         // do something on error
9106      *         if (canRecover(rejection)) {
9107      *           return responseOrNewPromise
9108      *         }
9109      *         return $q.reject(rejection);
9110      *       },
9111      *
9112      *
9113      *
9114      *       // optional method
9115      *       'response': function(response) {
9116      *         // do something on success
9117      *         return response;
9118      *       },
9119      *
9120      *       // optional method
9121      *      'responseError': function(rejection) {
9122      *         // do something on error
9123      *         if (canRecover(rejection)) {
9124      *           return responseOrNewPromise
9125      *         }
9126      *         return $q.reject(rejection);
9127      *       }
9128      *     };
9129      *   });
9130      *
9131      *   $httpProvider.interceptors.push('myHttpInterceptor');
9132      *
9133      *
9134      *   // alternatively, register the interceptor via an anonymous factory
9135      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
9136      *     return {
9137      *      'request': function(config) {
9138      *          // same as above
9139      *       },
9140      *
9141      *       'response': function(response) {
9142      *          // same as above
9143      *       }
9144      *     };
9145      *   });
9146      * ```
9147      *
9148      * ## Security Considerations
9149      *
9150      * When designing web applications, consider security threats from:
9151      *
9152      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9153      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
9154      *
9155      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
9156      * pre-configured with strategies that address these issues, but for this to work backend server
9157      * cooperation is required.
9158      *
9159      * ### JSON Vulnerability Protection
9160      *
9161      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9162      * allows third party website to turn your JSON resource URL into
9163      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
9164      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
9165      * Angular will automatically strip the prefix before processing it as JSON.
9166      *
9167      * For example if your server needs to return:
9168      * ```js
9169      * ['one','two']
9170      * ```
9171      *
9172      * which is vulnerable to attack, your server can return:
9173      * ```js
9174      * )]}',
9175      * ['one','two']
9176      * ```
9177      *
9178      * Angular will strip the prefix, before processing the JSON.
9179      *
9180      *
9181      * ### Cross Site Request Forgery (XSRF) Protection
9182      *
9183      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
9184      * an unauthorized site can gain your user's private data. Angular provides a mechanism
9185      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
9186      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
9187      * JavaScript that runs on your domain could read the cookie, your server can be assured that
9188      * the XHR came from JavaScript running on your domain. The header will not be set for
9189      * cross-domain requests.
9190      *
9191      * To take advantage of this, your server needs to set a token in a JavaScript readable session
9192      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
9193      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
9194      * that only JavaScript running on your domain could have sent the request. The token must be
9195      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
9196      * making up its own tokens). We recommend that the token is a digest of your site's
9197      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
9198      * for added security.
9199      *
9200      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
9201      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
9202      * or the per-request config object.
9203      *
9204      *
9205      * @param {object} config Object describing the request to be made and how it should be
9206      *    processed. The object has following properties:
9207      *
9208      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
9209      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
9210      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
9211      *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
9212      *      JSONified.
9213      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
9214      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
9215      *      HTTP headers to send to the server. If the return value of a function is null, the
9216      *      header will not be sent.
9217      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
9218      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
9219      *    - **transformRequest** –
9220      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
9221      *      transform function or an array of such functions. The transform function takes the http
9222      *      request body and headers and returns its transformed (typically serialized) version.
9223      *      See {@link ng.$http#overriding-the-default-transformations-per-request
9224      *      Overriding the Default Transformations}
9225      *    - **transformResponse** –
9226      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
9227      *      transform function or an array of such functions. The transform function takes the http
9228      *      response body, headers and status and returns its transformed (typically deserialized) version.
9229      *      See {@link ng.$http#overriding-the-default-transformations-per-request
9230      *      Overriding the Default Transformations}
9231      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
9232      *      GET request, otherwise if a cache instance built with
9233      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
9234      *      caching.
9235      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
9236      *      that should abort the request when resolved.
9237      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
9238      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
9239      *      for more information.
9240      *    - **responseType** - `{string}` - see
9241      *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
9242      *
9243      * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
9244      *   standard `then` method and two http specific methods: `success` and `error`. The `then`
9245      *   method takes two arguments a success and an error callback which will be called with a
9246      *   response object. The `success` and `error` methods take a single argument - a function that
9247      *   will be called when the request succeeds or fails respectively. The arguments passed into
9248      *   these functions are destructured representation of the response object passed into the
9249      *   `then` method. The response object has these properties:
9250      *
9251      *   - **data** – `{string|Object}` – The response body transformed with the transform
9252      *     functions.
9253      *   - **status** – `{number}` – HTTP status code of the response.
9254      *   - **headers** – `{function([headerName])}` – Header getter function.
9255      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9256      *   - **statusText** – `{string}` – HTTP status text of the response.
9257      *
9258      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
9259      *   requests. This is primarily meant to be used for debugging purposes.
9260      *
9261      *
9262      * @example
9263 <example module="httpExample">
9264 <file name="index.html">
9265   <div ng-controller="FetchController">
9266     <select ng-model="method">
9267       <option>GET</option>
9268       <option>JSONP</option>
9269     </select>
9270     <input type="text" ng-model="url" size="80"/>
9271     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
9272     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
9273     <button id="samplejsonpbtn"
9274       ng-click="updateModel('JSONP',
9275                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
9276       Sample JSONP
9277     </button>
9278     <button id="invalidjsonpbtn"
9279       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
9280         Invalid JSONP
9281       </button>
9282     <pre>http status code: {{status}}</pre>
9283     <pre>http response data: {{data}}</pre>
9284   </div>
9285 </file>
9286 <file name="script.js">
9287   angular.module('httpExample', [])
9288     .controller('FetchController', ['$scope', '$http', '$templateCache',
9289       function($scope, $http, $templateCache) {
9290         $scope.method = 'GET';
9291         $scope.url = 'http-hello.html';
9292
9293         $scope.fetch = function() {
9294           $scope.code = null;
9295           $scope.response = null;
9296
9297           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
9298             success(function(data, status) {
9299               $scope.status = status;
9300               $scope.data = data;
9301             }).
9302             error(function(data, status) {
9303               $scope.data = data || "Request failed";
9304               $scope.status = status;
9305           });
9306         };
9307
9308         $scope.updateModel = function(method, url) {
9309           $scope.method = method;
9310           $scope.url = url;
9311         };
9312       }]);
9313 </file>
9314 <file name="http-hello.html">
9315   Hello, $http!
9316 </file>
9317 <file name="protractor.js" type="protractor">
9318   var status = element(by.binding('status'));
9319   var data = element(by.binding('data'));
9320   var fetchBtn = element(by.id('fetchbtn'));
9321   var sampleGetBtn = element(by.id('samplegetbtn'));
9322   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
9323   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
9324
9325   it('should make an xhr GET request', function() {
9326     sampleGetBtn.click();
9327     fetchBtn.click();
9328     expect(status.getText()).toMatch('200');
9329     expect(data.getText()).toMatch(/Hello, \$http!/);
9330   });
9331
9332 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
9333 // it('should make a JSONP request to angularjs.org', function() {
9334 //   sampleJsonpBtn.click();
9335 //   fetchBtn.click();
9336 //   expect(status.getText()).toMatch('200');
9337 //   expect(data.getText()).toMatch(/Super Hero!/);
9338 // });
9339
9340   it('should make JSONP request to invalid URL and invoke the error handler',
9341       function() {
9342     invalidJsonpBtn.click();
9343     fetchBtn.click();
9344     expect(status.getText()).toMatch('0');
9345     expect(data.getText()).toMatch('Request failed');
9346   });
9347 </file>
9348 </example>
9349      */
9350     function $http(requestConfig) {
9351
9352       if (!angular.isObject(requestConfig)) {
9353         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
9354       }
9355
9356       var config = extend({
9357         method: 'get',
9358         transformRequest: defaults.transformRequest,
9359         transformResponse: defaults.transformResponse
9360       }, requestConfig);
9361
9362       config.headers = mergeHeaders(requestConfig);
9363       config.method = uppercase(config.method);
9364
9365       var serverRequest = function(config) {
9366         var headers = config.headers;
9367         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
9368
9369         // strip content-type if data is undefined
9370         if (isUndefined(reqData)) {
9371           forEach(headers, function(value, header) {
9372             if (lowercase(header) === 'content-type') {
9373                 delete headers[header];
9374             }
9375           });
9376         }
9377
9378         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
9379           config.withCredentials = defaults.withCredentials;
9380         }
9381
9382         // send request
9383         return sendReq(config, reqData).then(transformResponse, transformResponse);
9384       };
9385
9386       var chain = [serverRequest, undefined];
9387       var promise = $q.when(config);
9388
9389       // apply interceptors
9390       forEach(reversedInterceptors, function(interceptor) {
9391         if (interceptor.request || interceptor.requestError) {
9392           chain.unshift(interceptor.request, interceptor.requestError);
9393         }
9394         if (interceptor.response || interceptor.responseError) {
9395           chain.push(interceptor.response, interceptor.responseError);
9396         }
9397       });
9398
9399       while (chain.length) {
9400         var thenFn = chain.shift();
9401         var rejectFn = chain.shift();
9402
9403         promise = promise.then(thenFn, rejectFn);
9404       }
9405
9406       promise.success = function(fn) {
9407         promise.then(function(response) {
9408           fn(response.data, response.status, response.headers, config);
9409         });
9410         return promise;
9411       };
9412
9413       promise.error = function(fn) {
9414         promise.then(null, function(response) {
9415           fn(response.data, response.status, response.headers, config);
9416         });
9417         return promise;
9418       };
9419
9420       return promise;
9421
9422       function transformResponse(response) {
9423         // make a copy since the response must be cacheable
9424         var resp = extend({}, response);
9425         if (!response.data) {
9426           resp.data = response.data;
9427         } else {
9428           resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
9429         }
9430         return (isSuccess(response.status))
9431           ? resp
9432           : $q.reject(resp);
9433       }
9434
9435       function executeHeaderFns(headers) {
9436         var headerContent, processedHeaders = {};
9437
9438         forEach(headers, function(headerFn, header) {
9439           if (isFunction(headerFn)) {
9440             headerContent = headerFn();
9441             if (headerContent != null) {
9442               processedHeaders[header] = headerContent;
9443             }
9444           } else {
9445             processedHeaders[header] = headerFn;
9446           }
9447         });
9448
9449         return processedHeaders;
9450       }
9451
9452       function mergeHeaders(config) {
9453         var defHeaders = defaults.headers,
9454             reqHeaders = extend({}, config.headers),
9455             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
9456
9457         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
9458
9459         // using for-in instead of forEach to avoid unecessary iteration after header has been found
9460         defaultHeadersIteration:
9461         for (defHeaderName in defHeaders) {
9462           lowercaseDefHeaderName = lowercase(defHeaderName);
9463
9464           for (reqHeaderName in reqHeaders) {
9465             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
9466               continue defaultHeadersIteration;
9467             }
9468           }
9469
9470           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
9471         }
9472
9473         // execute if header value is a function for merged headers
9474         return executeHeaderFns(reqHeaders);
9475       }
9476     }
9477
9478     $http.pendingRequests = [];
9479
9480     /**
9481      * @ngdoc method
9482      * @name $http#get
9483      *
9484      * @description
9485      * Shortcut method to perform `GET` request.
9486      *
9487      * @param {string} url Relative or absolute URL specifying the destination of the request
9488      * @param {Object=} config Optional configuration object
9489      * @returns {HttpPromise} Future object
9490      */
9491
9492     /**
9493      * @ngdoc method
9494      * @name $http#delete
9495      *
9496      * @description
9497      * Shortcut method to perform `DELETE` request.
9498      *
9499      * @param {string} url Relative or absolute URL specifying the destination of the request
9500      * @param {Object=} config Optional configuration object
9501      * @returns {HttpPromise} Future object
9502      */
9503
9504     /**
9505      * @ngdoc method
9506      * @name $http#head
9507      *
9508      * @description
9509      * Shortcut method to perform `HEAD` request.
9510      *
9511      * @param {string} url Relative or absolute URL specifying the destination of the request
9512      * @param {Object=} config Optional configuration object
9513      * @returns {HttpPromise} Future object
9514      */
9515
9516     /**
9517      * @ngdoc method
9518      * @name $http#jsonp
9519      *
9520      * @description
9521      * Shortcut method to perform `JSONP` request.
9522      *
9523      * @param {string} url Relative or absolute URL specifying the destination of the request.
9524      *                     The name of the callback should be the string `JSON_CALLBACK`.
9525      * @param {Object=} config Optional configuration object
9526      * @returns {HttpPromise} Future object
9527      */
9528     createShortMethods('get', 'delete', 'head', 'jsonp');
9529
9530     /**
9531      * @ngdoc method
9532      * @name $http#post
9533      *
9534      * @description
9535      * Shortcut method to perform `POST` request.
9536      *
9537      * @param {string} url Relative or absolute URL specifying the destination of the request
9538      * @param {*} data Request content
9539      * @param {Object=} config Optional configuration object
9540      * @returns {HttpPromise} Future object
9541      */
9542
9543     /**
9544      * @ngdoc method
9545      * @name $http#put
9546      *
9547      * @description
9548      * Shortcut method to perform `PUT` request.
9549      *
9550      * @param {string} url Relative or absolute URL specifying the destination of the request
9551      * @param {*} data Request content
9552      * @param {Object=} config Optional configuration object
9553      * @returns {HttpPromise} Future object
9554      */
9555
9556      /**
9557       * @ngdoc method
9558       * @name $http#patch
9559       *
9560       * @description
9561       * Shortcut method to perform `PATCH` request.
9562       *
9563       * @param {string} url Relative or absolute URL specifying the destination of the request
9564       * @param {*} data Request content
9565       * @param {Object=} config Optional configuration object
9566       * @returns {HttpPromise} Future object
9567       */
9568     createShortMethodsWithData('post', 'put', 'patch');
9569
9570         /**
9571          * @ngdoc property
9572          * @name $http#defaults
9573          *
9574          * @description
9575          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
9576          * default headers, withCredentials as well as request and response transformations.
9577          *
9578          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
9579          */
9580     $http.defaults = defaults;
9581
9582
9583     return $http;
9584
9585
9586     function createShortMethods(names) {
9587       forEach(arguments, function(name) {
9588         $http[name] = function(url, config) {
9589           return $http(extend(config || {}, {
9590             method: name,
9591             url: url
9592           }));
9593         };
9594       });
9595     }
9596
9597
9598     function createShortMethodsWithData(name) {
9599       forEach(arguments, function(name) {
9600         $http[name] = function(url, data, config) {
9601           return $http(extend(config || {}, {
9602             method: name,
9603             url: url,
9604             data: data
9605           }));
9606         };
9607       });
9608     }
9609
9610
9611     /**
9612      * Makes the request.
9613      *
9614      * !!! ACCESSES CLOSURE VARS:
9615      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
9616      */
9617     function sendReq(config, reqData) {
9618       var deferred = $q.defer(),
9619           promise = deferred.promise,
9620           cache,
9621           cachedResp,
9622           reqHeaders = config.headers,
9623           url = buildUrl(config.url, config.params);
9624
9625       $http.pendingRequests.push(config);
9626       promise.then(removePendingReq, removePendingReq);
9627
9628
9629       if ((config.cache || defaults.cache) && config.cache !== false &&
9630           (config.method === 'GET' || config.method === 'JSONP')) {
9631         cache = isObject(config.cache) ? config.cache
9632               : isObject(defaults.cache) ? defaults.cache
9633               : defaultCache;
9634       }
9635
9636       if (cache) {
9637         cachedResp = cache.get(url);
9638         if (isDefined(cachedResp)) {
9639           if (isPromiseLike(cachedResp)) {
9640             // cached request has already been sent, but there is no response yet
9641             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
9642           } else {
9643             // serving from cache
9644             if (isArray(cachedResp)) {
9645               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
9646             } else {
9647               resolvePromise(cachedResp, 200, {}, 'OK');
9648             }
9649           }
9650         } else {
9651           // put the promise for the non-transformed response into cache as a placeholder
9652           cache.put(url, promise);
9653         }
9654       }
9655
9656
9657       // if we won't have the response in cache, set the xsrf headers and
9658       // send the request to the backend
9659       if (isUndefined(cachedResp)) {
9660         var xsrfValue = urlIsSameOrigin(config.url)
9661             ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
9662             : undefined;
9663         if (xsrfValue) {
9664           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
9665         }
9666
9667         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
9668             config.withCredentials, config.responseType);
9669       }
9670
9671       return promise;
9672
9673
9674       /**
9675        * Callback registered to $httpBackend():
9676        *  - caches the response if desired
9677        *  - resolves the raw $http promise
9678        *  - calls $apply
9679        */
9680       function done(status, response, headersString, statusText) {
9681         if (cache) {
9682           if (isSuccess(status)) {
9683             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
9684           } else {
9685             // remove promise from the cache
9686             cache.remove(url);
9687           }
9688         }
9689
9690         function resolveHttpPromise() {
9691           resolvePromise(response, status, headersString, statusText);
9692         }
9693
9694         if (useApplyAsync) {
9695           $rootScope.$applyAsync(resolveHttpPromise);
9696         } else {
9697           resolveHttpPromise();
9698           if (!$rootScope.$$phase) $rootScope.$apply();
9699         }
9700       }
9701
9702
9703       /**
9704        * Resolves the raw $http promise.
9705        */
9706       function resolvePromise(response, status, headers, statusText) {
9707         // normalize internal statuses to 0
9708         status = Math.max(status, 0);
9709
9710         (isSuccess(status) ? deferred.resolve : deferred.reject)({
9711           data: response,
9712           status: status,
9713           headers: headersGetter(headers),
9714           config: config,
9715           statusText: statusText
9716         });
9717       }
9718
9719       function resolvePromiseWithResult(result) {
9720         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
9721       }
9722
9723       function removePendingReq() {
9724         var idx = $http.pendingRequests.indexOf(config);
9725         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
9726       }
9727     }
9728
9729
9730     function buildUrl(url, params) {
9731       if (!params) return url;
9732       var parts = [];
9733       forEachSorted(params, function(value, key) {
9734         if (value === null || isUndefined(value)) return;
9735         if (!isArray(value)) value = [value];
9736
9737         forEach(value, function(v) {
9738           if (isObject(v)) {
9739             if (isDate(v)) {
9740               v = v.toISOString();
9741             } else {
9742               v = toJson(v);
9743             }
9744           }
9745           parts.push(encodeUriQuery(key) + '=' +
9746                      encodeUriQuery(v));
9747         });
9748       });
9749       if (parts.length > 0) {
9750         url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
9751       }
9752       return url;
9753     }
9754   }];
9755 }
9756
9757 function createXhr() {
9758     return new window.XMLHttpRequest();
9759 }
9760
9761 /**
9762  * @ngdoc service
9763  * @name $httpBackend
9764  * @requires $window
9765  * @requires $document
9766  *
9767  * @description
9768  * HTTP backend used by the {@link ng.$http service} that delegates to
9769  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
9770  *
9771  * You should never need to use this service directly, instead use the higher-level abstractions:
9772  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
9773  *
9774  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
9775  * $httpBackend} which can be trained with responses.
9776  */
9777 function $HttpBackendProvider() {
9778   this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
9779     return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
9780   }];
9781 }
9782
9783 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
9784   // TODO(vojta): fix the signature
9785   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
9786     $browser.$$incOutstandingRequestCount();
9787     url = url || $browser.url();
9788
9789     if (lowercase(method) == 'jsonp') {
9790       var callbackId = '_' + (callbacks.counter++).toString(36);
9791       callbacks[callbackId] = function(data) {
9792         callbacks[callbackId].data = data;
9793         callbacks[callbackId].called = true;
9794       };
9795
9796       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
9797           callbackId, function(status, text) {
9798         completeRequest(callback, status, callbacks[callbackId].data, "", text);
9799         callbacks[callbackId] = noop;
9800       });
9801     } else {
9802
9803       var xhr = createXhr();
9804
9805       xhr.open(method, url, true);
9806       forEach(headers, function(value, key) {
9807         if (isDefined(value)) {
9808             xhr.setRequestHeader(key, value);
9809         }
9810       });
9811
9812       xhr.onload = function requestLoaded() {
9813         var statusText = xhr.statusText || '';
9814
9815         // responseText is the old-school way of retrieving response (supported by IE8 & 9)
9816         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
9817         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
9818
9819         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
9820         var status = xhr.status === 1223 ? 204 : xhr.status;
9821
9822         // fix status code when it is 0 (0 status is undocumented).
9823         // Occurs when accessing file resources or on Android 4.1 stock browser
9824         // while retrieving files from application cache.
9825         if (status === 0) {
9826           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
9827         }
9828
9829         completeRequest(callback,
9830             status,
9831             response,
9832             xhr.getAllResponseHeaders(),
9833             statusText);
9834       };
9835
9836       var requestError = function() {
9837         // The response is always empty
9838         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
9839         completeRequest(callback, -1, null, null, '');
9840       };
9841
9842       xhr.onerror = requestError;
9843       xhr.onabort = requestError;
9844
9845       if (withCredentials) {
9846         xhr.withCredentials = true;
9847       }
9848
9849       if (responseType) {
9850         try {
9851           xhr.responseType = responseType;
9852         } catch (e) {
9853           // WebKit added support for the json responseType value on 09/03/2013
9854           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
9855           // known to throw when setting the value "json" as the response type. Other older
9856           // browsers implementing the responseType
9857           //
9858           // The json response type can be ignored if not supported, because JSON payloads are
9859           // parsed on the client-side regardless.
9860           if (responseType !== 'json') {
9861             throw e;
9862           }
9863         }
9864       }
9865
9866       xhr.send(post || null);
9867     }
9868
9869     if (timeout > 0) {
9870       var timeoutId = $browserDefer(timeoutRequest, timeout);
9871     } else if (isPromiseLike(timeout)) {
9872       timeout.then(timeoutRequest);
9873     }
9874
9875
9876     function timeoutRequest() {
9877       jsonpDone && jsonpDone();
9878       xhr && xhr.abort();
9879     }
9880
9881     function completeRequest(callback, status, response, headersString, statusText) {
9882       // cancel timeout and subsequent timeout promise resolution
9883       if (timeoutId !== undefined) {
9884         $browserDefer.cancel(timeoutId);
9885       }
9886       jsonpDone = xhr = null;
9887
9888       callback(status, response, headersString, statusText);
9889       $browser.$$completeOutstandingRequest(noop);
9890     }
9891   };
9892
9893   function jsonpReq(url, callbackId, done) {
9894     // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
9895     // - fetches local scripts via XHR and evals them
9896     // - adds and immediately removes script elements from the document
9897     var script = rawDocument.createElement('script'), callback = null;
9898     script.type = "text/javascript";
9899     script.src = url;
9900     script.async = true;
9901
9902     callback = function(event) {
9903       removeEventListenerFn(script, "load", callback);
9904       removeEventListenerFn(script, "error", callback);
9905       rawDocument.body.removeChild(script);
9906       script = null;
9907       var status = -1;
9908       var text = "unknown";
9909
9910       if (event) {
9911         if (event.type === "load" && !callbacks[callbackId].called) {
9912           event = { type: "error" };
9913         }
9914         text = event.type;
9915         status = event.type === "error" ? 404 : 200;
9916       }
9917
9918       if (done) {
9919         done(status, text);
9920       }
9921     };
9922
9923     addEventListenerFn(script, "load", callback);
9924     addEventListenerFn(script, "error", callback);
9925     rawDocument.body.appendChild(script);
9926     return callback;
9927   }
9928 }
9929
9930 var $interpolateMinErr = minErr('$interpolate');
9931
9932 /**
9933  * @ngdoc provider
9934  * @name $interpolateProvider
9935  *
9936  * @description
9937  *
9938  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
9939  *
9940  * @example
9941 <example module="customInterpolationApp">
9942 <file name="index.html">
9943 <script>
9944   var customInterpolationApp = angular.module('customInterpolationApp', []);
9945
9946   customInterpolationApp.config(function($interpolateProvider) {
9947     $interpolateProvider.startSymbol('//');
9948     $interpolateProvider.endSymbol('//');
9949   });
9950
9951
9952   customInterpolationApp.controller('DemoController', function() {
9953       this.label = "This binding is brought you by // interpolation symbols.";
9954   });
9955 </script>
9956 <div ng-app="App" ng-controller="DemoController as demo">
9957     //demo.label//
9958 </div>
9959 </file>
9960 <file name="protractor.js" type="protractor">
9961   it('should interpolate binding with custom symbols', function() {
9962     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
9963   });
9964 </file>
9965 </example>
9966  */
9967 function $InterpolateProvider() {
9968   var startSymbol = '{{';
9969   var endSymbol = '}}';
9970
9971   /**
9972    * @ngdoc method
9973    * @name $interpolateProvider#startSymbol
9974    * @description
9975    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
9976    *
9977    * @param {string=} value new value to set the starting symbol to.
9978    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
9979    */
9980   this.startSymbol = function(value) {
9981     if (value) {
9982       startSymbol = value;
9983       return this;
9984     } else {
9985       return startSymbol;
9986     }
9987   };
9988
9989   /**
9990    * @ngdoc method
9991    * @name $interpolateProvider#endSymbol
9992    * @description
9993    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
9994    *
9995    * @param {string=} value new value to set the ending symbol to.
9996    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
9997    */
9998   this.endSymbol = function(value) {
9999     if (value) {
10000       endSymbol = value;
10001       return this;
10002     } else {
10003       return endSymbol;
10004     }
10005   };
10006
10007
10008   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10009     var startSymbolLength = startSymbol.length,
10010         endSymbolLength = endSymbol.length,
10011         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
10012         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
10013
10014     function escape(ch) {
10015       return '\\\\\\' + ch;
10016     }
10017
10018     /**
10019      * @ngdoc service
10020      * @name $interpolate
10021      * @kind function
10022      *
10023      * @requires $parse
10024      * @requires $sce
10025      *
10026      * @description
10027      *
10028      * Compiles a string with markup into an interpolation function. This service is used by the
10029      * HTML {@link ng.$compile $compile} service for data binding. See
10030      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
10031      * interpolation markup.
10032      *
10033      *
10034      * ```js
10035      *   var $interpolate = ...; // injected
10036      *   var exp = $interpolate('Hello {{name | uppercase}}!');
10037      *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
10038      * ```
10039      *
10040      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
10041      * `true`, the interpolation function will return `undefined` unless all embedded expressions
10042      * evaluate to a value other than `undefined`.
10043      *
10044      * ```js
10045      *   var $interpolate = ...; // injected
10046      *   var context = {greeting: 'Hello', name: undefined };
10047      *
10048      *   // default "forgiving" mode
10049      *   var exp = $interpolate('{{greeting}} {{name}}!');
10050      *   expect(exp(context)).toEqual('Hello !');
10051      *
10052      *   // "allOrNothing" mode
10053      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
10054      *   expect(exp(context)).toBeUndefined();
10055      *   context.name = 'Angular';
10056      *   expect(exp(context)).toEqual('Hello Angular!');
10057      * ```
10058      *
10059      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
10060      *
10061      * ####Escaped Interpolation
10062      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
10063      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
10064      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
10065      * or binding.
10066      *
10067      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
10068      * degree, while also enabling code examples to work without relying on the
10069      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
10070      *
10071      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
10072      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
10073      * interpolation start/end markers with their escaped counterparts.**
10074      *
10075      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
10076      * output when the $interpolate service processes the text. So, for HTML elements interpolated
10077      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
10078      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
10079      * this is typically useful only when user-data is used in rendering a template from the server, or
10080      * when otherwise untrusted data is used by a directive.
10081      *
10082      * <example>
10083      *  <file name="index.html">
10084      *    <div ng-init="username='A user'">
10085      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
10086      *        </p>
10087      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
10088      *        application, but fails to accomplish their task, because the server has correctly
10089      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
10090      *        characters.</p>
10091      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
10092      *        from the database by an administrator.</p>
10093      *    </div>
10094      *  </file>
10095      * </example>
10096      *
10097      * @param {string} text The text with markup to interpolate.
10098      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
10099      *    embedded expression in order to return an interpolation function. Strings with no
10100      *    embedded expression will return null for the interpolation function.
10101      * @param {string=} trustedContext when provided, the returned function passes the interpolated
10102      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
10103      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
10104      *    provides Strict Contextual Escaping for details.
10105      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
10106      *    unless all embedded expressions evaluate to a value other than `undefined`.
10107      * @returns {function(context)} an interpolation function which is used to compute the
10108      *    interpolated string. The function has these parameters:
10109      *
10110      * - `context`: evaluation context for all expressions embedded in the interpolated text
10111      */
10112     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
10113       allOrNothing = !!allOrNothing;
10114       var startIndex,
10115           endIndex,
10116           index = 0,
10117           expressions = [],
10118           parseFns = [],
10119           textLength = text.length,
10120           exp,
10121           concat = [],
10122           expressionPositions = [];
10123
10124       while (index < textLength) {
10125         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
10126              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
10127           if (index !== startIndex) {
10128             concat.push(unescapeText(text.substring(index, startIndex)));
10129           }
10130           exp = text.substring(startIndex + startSymbolLength, endIndex);
10131           expressions.push(exp);
10132           parseFns.push($parse(exp, parseStringifyInterceptor));
10133           index = endIndex + endSymbolLength;
10134           expressionPositions.push(concat.length);
10135           concat.push('');
10136         } else {
10137           // we did not find an interpolation, so we have to add the remainder to the separators array
10138           if (index !== textLength) {
10139             concat.push(unescapeText(text.substring(index)));
10140           }
10141           break;
10142         }
10143       }
10144
10145       // Concatenating expressions makes it hard to reason about whether some combination of
10146       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
10147       // single expression be used for iframe[src], object[src], etc., we ensure that the value
10148       // that's used is assigned or constructed by some JS code somewhere that is more testable or
10149       // make it obvious that you bound the value to some user controlled value.  This helps reduce
10150       // the load when auditing for XSS issues.
10151       if (trustedContext && concat.length > 1) {
10152           throw $interpolateMinErr('noconcat',
10153               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10154               "interpolations that concatenate multiple expressions when a trusted value is " +
10155               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10156       }
10157
10158       if (!mustHaveExpression || expressions.length) {
10159         var compute = function(values) {
10160           for (var i = 0, ii = expressions.length; i < ii; i++) {
10161             if (allOrNothing && isUndefined(values[i])) return;
10162             concat[expressionPositions[i]] = values[i];
10163           }
10164           return concat.join('');
10165         };
10166
10167         var getValue = function(value) {
10168           return trustedContext ?
10169             $sce.getTrusted(trustedContext, value) :
10170             $sce.valueOf(value);
10171         };
10172
10173         var stringify = function(value) {
10174           if (value == null) { // null || undefined
10175             return '';
10176           }
10177           switch (typeof value) {
10178             case 'string':
10179               break;
10180             case 'number':
10181               value = '' + value;
10182               break;
10183             default:
10184               value = toJson(value);
10185           }
10186
10187           return value;
10188         };
10189
10190         return extend(function interpolationFn(context) {
10191             var i = 0;
10192             var ii = expressions.length;
10193             var values = new Array(ii);
10194
10195             try {
10196               for (; i < ii; i++) {
10197                 values[i] = parseFns[i](context);
10198               }
10199
10200               return compute(values);
10201             } catch (err) {
10202               var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10203                   err.toString());
10204               $exceptionHandler(newErr);
10205             }
10206
10207           }, {
10208           // all of these properties are undocumented for now
10209           exp: text, //just for compatibility with regular watchers created via $watch
10210           expressions: expressions,
10211           $$watchDelegate: function(scope, listener, objectEquality) {
10212             var lastValue;
10213             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
10214               var currValue = compute(values);
10215               if (isFunction(listener)) {
10216                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
10217               }
10218               lastValue = currValue;
10219             }, objectEquality);
10220           }
10221         });
10222       }
10223
10224       function unescapeText(text) {
10225         return text.replace(escapedStartRegexp, startSymbol).
10226           replace(escapedEndRegexp, endSymbol);
10227       }
10228
10229       function parseStringifyInterceptor(value) {
10230         try {
10231           value = getValue(value);
10232           return allOrNothing && !isDefined(value) ? value : stringify(value);
10233         } catch (err) {
10234           var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10235             err.toString());
10236           $exceptionHandler(newErr);
10237         }
10238       }
10239     }
10240
10241
10242     /**
10243      * @ngdoc method
10244      * @name $interpolate#startSymbol
10245      * @description
10246      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
10247      *
10248      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
10249      * the symbol.
10250      *
10251      * @returns {string} start symbol.
10252      */
10253     $interpolate.startSymbol = function() {
10254       return startSymbol;
10255     };
10256
10257
10258     /**
10259      * @ngdoc method
10260      * @name $interpolate#endSymbol
10261      * @description
10262      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10263      *
10264      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
10265      * the symbol.
10266      *
10267      * @returns {string} end symbol.
10268      */
10269     $interpolate.endSymbol = function() {
10270       return endSymbol;
10271     };
10272
10273     return $interpolate;
10274   }];
10275 }
10276
10277 function $IntervalProvider() {
10278   this.$get = ['$rootScope', '$window', '$q', '$$q',
10279        function($rootScope,   $window,   $q,   $$q) {
10280     var intervals = {};
10281
10282
10283      /**
10284       * @ngdoc service
10285       * @name $interval
10286       *
10287       * @description
10288       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
10289       * milliseconds.
10290       *
10291       * The return value of registering an interval function is a promise. This promise will be
10292       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
10293       * run indefinitely if `count` is not defined. The value of the notification will be the
10294       * number of iterations that have run.
10295       * To cancel an interval, call `$interval.cancel(promise)`.
10296       *
10297       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
10298       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
10299       * time.
10300       *
10301       * <div class="alert alert-warning">
10302       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
10303       * with them.  In particular they are not automatically destroyed when a controller's scope or a
10304       * directive's element are destroyed.
10305       * You should take this into consideration and make sure to always cancel the interval at the
10306       * appropriate moment.  See the example below for more details on how and when to do this.
10307       * </div>
10308       *
10309       * @param {function()} fn A function that should be called repeatedly.
10310       * @param {number} delay Number of milliseconds between each function call.
10311       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
10312       *   indefinitely.
10313       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
10314       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
10315       * @returns {promise} A promise which will be notified on each iteration.
10316       *
10317       * @example
10318       * <example module="intervalExample">
10319       * <file name="index.html">
10320       *   <script>
10321       *     angular.module('intervalExample', [])
10322       *       .controller('ExampleController', ['$scope', '$interval',
10323       *         function($scope, $interval) {
10324       *           $scope.format = 'M/d/yy h:mm:ss a';
10325       *           $scope.blood_1 = 100;
10326       *           $scope.blood_2 = 120;
10327       *
10328       *           var stop;
10329       *           $scope.fight = function() {
10330       *             // Don't start a new fight if we are already fighting
10331       *             if ( angular.isDefined(stop) ) return;
10332       *
10333       *             stop = $interval(function() {
10334       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10335       *                 $scope.blood_1 = $scope.blood_1 - 3;
10336       *                 $scope.blood_2 = $scope.blood_2 - 4;
10337       *               } else {
10338       *                 $scope.stopFight();
10339       *               }
10340       *             }, 100);
10341       *           };
10342       *
10343       *           $scope.stopFight = function() {
10344       *             if (angular.isDefined(stop)) {
10345       *               $interval.cancel(stop);
10346       *               stop = undefined;
10347       *             }
10348       *           };
10349       *
10350       *           $scope.resetFight = function() {
10351       *             $scope.blood_1 = 100;
10352       *             $scope.blood_2 = 120;
10353       *           };
10354       *
10355       *           $scope.$on('$destroy', function() {
10356       *             // Make sure that the interval is destroyed too
10357       *             $scope.stopFight();
10358       *           });
10359       *         }])
10360       *       // Register the 'myCurrentTime' directive factory method.
10361       *       // We inject $interval and dateFilter service since the factory method is DI.
10362       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
10363       *         function($interval, dateFilter) {
10364       *           // return the directive link function. (compile function not needed)
10365       *           return function(scope, element, attrs) {
10366       *             var format,  // date format
10367       *                 stopTime; // so that we can cancel the time updates
10368       *
10369       *             // used to update the UI
10370       *             function updateTime() {
10371       *               element.text(dateFilter(new Date(), format));
10372       *             }
10373       *
10374       *             // watch the expression, and update the UI on change.
10375       *             scope.$watch(attrs.myCurrentTime, function(value) {
10376       *               format = value;
10377       *               updateTime();
10378       *             });
10379       *
10380       *             stopTime = $interval(updateTime, 1000);
10381       *
10382       *             // listen on DOM destroy (removal) event, and cancel the next UI update
10383       *             // to prevent updating time after the DOM element was removed.
10384       *             element.on('$destroy', function() {
10385       *               $interval.cancel(stopTime);
10386       *             });
10387       *           }
10388       *         }]);
10389       *   </script>
10390       *
10391       *   <div>
10392       *     <div ng-controller="ExampleController">
10393       *       Date format: <input ng-model="format"> <hr/>
10394       *       Current time is: <span my-current-time="format"></span>
10395       *       <hr/>
10396       *       Blood 1 : <font color='red'>{{blood_1}}</font>
10397       *       Blood 2 : <font color='red'>{{blood_2}}</font>
10398       *       <button type="button" data-ng-click="fight()">Fight</button>
10399       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
10400       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
10401       *     </div>
10402       *   </div>
10403       *
10404       * </file>
10405       * </example>
10406       */
10407     function interval(fn, delay, count, invokeApply) {
10408       var setInterval = $window.setInterval,
10409           clearInterval = $window.clearInterval,
10410           iteration = 0,
10411           skipApply = (isDefined(invokeApply) && !invokeApply),
10412           deferred = (skipApply ? $$q : $q).defer(),
10413           promise = deferred.promise;
10414
10415       count = isDefined(count) ? count : 0;
10416
10417       promise.then(null, null, fn);
10418
10419       promise.$$intervalId = setInterval(function tick() {
10420         deferred.notify(iteration++);
10421
10422         if (count > 0 && iteration >= count) {
10423           deferred.resolve(iteration);
10424           clearInterval(promise.$$intervalId);
10425           delete intervals[promise.$$intervalId];
10426         }
10427
10428         if (!skipApply) $rootScope.$apply();
10429
10430       }, delay);
10431
10432       intervals[promise.$$intervalId] = deferred;
10433
10434       return promise;
10435     }
10436
10437
10438      /**
10439       * @ngdoc method
10440       * @name $interval#cancel
10441       *
10442       * @description
10443       * Cancels a task associated with the `promise`.
10444       *
10445       * @param {promise} promise returned by the `$interval` function.
10446       * @returns {boolean} Returns `true` if the task was successfully canceled.
10447       */
10448     interval.cancel = function(promise) {
10449       if (promise && promise.$$intervalId in intervals) {
10450         intervals[promise.$$intervalId].reject('canceled');
10451         $window.clearInterval(promise.$$intervalId);
10452         delete intervals[promise.$$intervalId];
10453         return true;
10454       }
10455       return false;
10456     };
10457
10458     return interval;
10459   }];
10460 }
10461
10462 /**
10463  * @ngdoc service
10464  * @name $locale
10465  *
10466  * @description
10467  * $locale service provides localization rules for various Angular components. As of right now the
10468  * only public api is:
10469  *
10470  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
10471  */
10472 function $LocaleProvider() {
10473   this.$get = function() {
10474     return {
10475       id: 'en-us',
10476
10477       NUMBER_FORMATS: {
10478         DECIMAL_SEP: '.',
10479         GROUP_SEP: ',',
10480         PATTERNS: [
10481           { // Decimal Pattern
10482             minInt: 1,
10483             minFrac: 0,
10484             maxFrac: 3,
10485             posPre: '',
10486             posSuf: '',
10487             negPre: '-',
10488             negSuf: '',
10489             gSize: 3,
10490             lgSize: 3
10491           },{ //Currency Pattern
10492             minInt: 1,
10493             minFrac: 2,
10494             maxFrac: 2,
10495             posPre: '\u00A4',
10496             posSuf: '',
10497             negPre: '(\u00A4',
10498             negSuf: ')',
10499             gSize: 3,
10500             lgSize: 3
10501           }
10502         ],
10503         CURRENCY_SYM: '$'
10504       },
10505
10506       DATETIME_FORMATS: {
10507         MONTH:
10508             'January,February,March,April,May,June,July,August,September,October,November,December'
10509             .split(','),
10510         SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
10511         DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
10512         SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
10513         AMPMS: ['AM','PM'],
10514         medium: 'MMM d, y h:mm:ss a',
10515         'short': 'M/d/yy h:mm a',
10516         fullDate: 'EEEE, MMMM d, y',
10517         longDate: 'MMMM d, y',
10518         mediumDate: 'MMM d, y',
10519         shortDate: 'M/d/yy',
10520         mediumTime: 'h:mm:ss a',
10521         shortTime: 'h:mm a',
10522         ERANAMES: [
10523           "Before Christ",
10524           "Anno Domini"
10525         ],
10526         ERAS: [
10527           "BC",
10528           "AD"
10529         ]
10530       },
10531
10532       pluralCat: function(num) {
10533         if (num === 1) {
10534           return 'one';
10535         }
10536         return 'other';
10537       }
10538     };
10539   };
10540 }
10541
10542 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
10543     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
10544 var $locationMinErr = minErr('$location');
10545
10546
10547 /**
10548  * Encode path using encodeUriSegment, ignoring forward slashes
10549  *
10550  * @param {string} path Path to encode
10551  * @returns {string}
10552  */
10553 function encodePath(path) {
10554   var segments = path.split('/'),
10555       i = segments.length;
10556
10557   while (i--) {
10558     segments[i] = encodeUriSegment(segments[i]);
10559   }
10560
10561   return segments.join('/');
10562 }
10563
10564 function parseAbsoluteUrl(absoluteUrl, locationObj) {
10565   var parsedUrl = urlResolve(absoluteUrl);
10566
10567   locationObj.$$protocol = parsedUrl.protocol;
10568   locationObj.$$host = parsedUrl.hostname;
10569   locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
10570 }
10571
10572
10573 function parseAppUrl(relativeUrl, locationObj) {
10574   var prefixed = (relativeUrl.charAt(0) !== '/');
10575   if (prefixed) {
10576     relativeUrl = '/' + relativeUrl;
10577   }
10578   var match = urlResolve(relativeUrl);
10579   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
10580       match.pathname.substring(1) : match.pathname);
10581   locationObj.$$search = parseKeyValue(match.search);
10582   locationObj.$$hash = decodeURIComponent(match.hash);
10583
10584   // make sure path starts with '/';
10585   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
10586     locationObj.$$path = '/' + locationObj.$$path;
10587   }
10588 }
10589
10590
10591 /**
10592  *
10593  * @param {string} begin
10594  * @param {string} whole
10595  * @returns {string} returns text from whole after begin or undefined if it does not begin with
10596  *                   expected string.
10597  */
10598 function beginsWith(begin, whole) {
10599   if (whole.indexOf(begin) === 0) {
10600     return whole.substr(begin.length);
10601   }
10602 }
10603
10604
10605 function stripHash(url) {
10606   var index = url.indexOf('#');
10607   return index == -1 ? url : url.substr(0, index);
10608 }
10609
10610 function trimEmptyHash(url) {
10611   return url.replace(/(#.+)|#$/, '$1');
10612 }
10613
10614
10615 function stripFile(url) {
10616   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
10617 }
10618
10619 /* return the server only (scheme://host:port) */
10620 function serverBase(url) {
10621   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
10622 }
10623
10624
10625 /**
10626  * LocationHtml5Url represents an url
10627  * This object is exposed as $location service when HTML5 mode is enabled and supported
10628  *
10629  * @constructor
10630  * @param {string} appBase application base URL
10631  * @param {string} basePrefix url path prefix
10632  */
10633 function LocationHtml5Url(appBase, basePrefix) {
10634   this.$$html5 = true;
10635   basePrefix = basePrefix || '';
10636   var appBaseNoFile = stripFile(appBase);
10637   parseAbsoluteUrl(appBase, this);
10638
10639
10640   /**
10641    * Parse given html5 (regular) url string into properties
10642    * @param {string} url HTML5 url
10643    * @private
10644    */
10645   this.$$parse = function(url) {
10646     var pathUrl = beginsWith(appBaseNoFile, url);
10647     if (!isString(pathUrl)) {
10648       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
10649           appBaseNoFile);
10650     }
10651
10652     parseAppUrl(pathUrl, this);
10653
10654     if (!this.$$path) {
10655       this.$$path = '/';
10656     }
10657
10658     this.$$compose();
10659   };
10660
10661   /**
10662    * Compose url and update `absUrl` property
10663    * @private
10664    */
10665   this.$$compose = function() {
10666     var search = toKeyValue(this.$$search),
10667         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10668
10669     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10670     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
10671   };
10672
10673   this.$$parseLinkUrl = function(url, relHref) {
10674     if (relHref && relHref[0] === '#') {
10675       // special case for links to hash fragments:
10676       // keep the old url and only replace the hash fragment
10677       this.hash(relHref.slice(1));
10678       return true;
10679     }
10680     var appUrl, prevAppUrl;
10681     var rewrittenUrl;
10682
10683     if ((appUrl = beginsWith(appBase, url)) !== undefined) {
10684       prevAppUrl = appUrl;
10685       if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
10686         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
10687       } else {
10688         rewrittenUrl = appBase + prevAppUrl;
10689       }
10690     } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
10691       rewrittenUrl = appBaseNoFile + appUrl;
10692     } else if (appBaseNoFile == url + '/') {
10693       rewrittenUrl = appBaseNoFile;
10694     }
10695     if (rewrittenUrl) {
10696       this.$$parse(rewrittenUrl);
10697     }
10698     return !!rewrittenUrl;
10699   };
10700 }
10701
10702
10703 /**
10704  * LocationHashbangUrl represents url
10705  * This object is exposed as $location service when developer doesn't opt into html5 mode.
10706  * It also serves as the base class for html5 mode fallback on legacy browsers.
10707  *
10708  * @constructor
10709  * @param {string} appBase application base URL
10710  * @param {string} hashPrefix hashbang prefix
10711  */
10712 function LocationHashbangUrl(appBase, hashPrefix) {
10713   var appBaseNoFile = stripFile(appBase);
10714
10715   parseAbsoluteUrl(appBase, this);
10716
10717
10718   /**
10719    * Parse given hashbang url into properties
10720    * @param {string} url Hashbang url
10721    * @private
10722    */
10723   this.$$parse = function(url) {
10724     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
10725     var withoutHashUrl;
10726
10727     if (withoutBaseUrl.charAt(0) === '#') {
10728
10729       // The rest of the url starts with a hash so we have
10730       // got either a hashbang path or a plain hash fragment
10731       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
10732       if (isUndefined(withoutHashUrl)) {
10733         // There was no hashbang prefix so we just have a hash fragment
10734         withoutHashUrl = withoutBaseUrl;
10735       }
10736
10737     } else {
10738       // There was no hashbang path nor hash fragment:
10739       // If we are in HTML5 mode we use what is left as the path;
10740       // Otherwise we ignore what is left
10741       withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
10742     }
10743
10744     parseAppUrl(withoutHashUrl, this);
10745
10746     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
10747
10748     this.$$compose();
10749
10750     /*
10751      * In Windows, on an anchor node on documents loaded from
10752      * the filesystem, the browser will return a pathname
10753      * prefixed with the drive name ('/C:/path') when a
10754      * pathname without a drive is set:
10755      *  * a.setAttribute('href', '/foo')
10756      *   * a.pathname === '/C:/foo' //true
10757      *
10758      * Inside of Angular, we're always using pathnames that
10759      * do not include drive names for routing.
10760      */
10761     function removeWindowsDriveName(path, url, base) {
10762       /*
10763       Matches paths for file protocol on windows,
10764       such as /C:/foo/bar, and captures only /foo/bar.
10765       */
10766       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
10767
10768       var firstPathSegmentMatch;
10769
10770       //Get the relative path from the input URL.
10771       if (url.indexOf(base) === 0) {
10772         url = url.replace(base, '');
10773       }
10774
10775       // The input URL intentionally contains a first path segment that ends with a colon.
10776       if (windowsFilePathExp.exec(url)) {
10777         return path;
10778       }
10779
10780       firstPathSegmentMatch = windowsFilePathExp.exec(path);
10781       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
10782     }
10783   };
10784
10785   /**
10786    * Compose hashbang url and update `absUrl` property
10787    * @private
10788    */
10789   this.$$compose = function() {
10790     var search = toKeyValue(this.$$search),
10791         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10792
10793     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10794     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
10795   };
10796
10797   this.$$parseLinkUrl = function(url, relHref) {
10798     if (stripHash(appBase) == stripHash(url)) {
10799       this.$$parse(url);
10800       return true;
10801     }
10802     return false;
10803   };
10804 }
10805
10806
10807 /**
10808  * LocationHashbangUrl represents url
10809  * This object is exposed as $location service when html5 history api is enabled but the browser
10810  * does not support it.
10811  *
10812  * @constructor
10813  * @param {string} appBase application base URL
10814  * @param {string} hashPrefix hashbang prefix
10815  */
10816 function LocationHashbangInHtml5Url(appBase, hashPrefix) {
10817   this.$$html5 = true;
10818   LocationHashbangUrl.apply(this, arguments);
10819
10820   var appBaseNoFile = stripFile(appBase);
10821
10822   this.$$parseLinkUrl = function(url, relHref) {
10823     if (relHref && relHref[0] === '#') {
10824       // special case for links to hash fragments:
10825       // keep the old url and only replace the hash fragment
10826       this.hash(relHref.slice(1));
10827       return true;
10828     }
10829
10830     var rewrittenUrl;
10831     var appUrl;
10832
10833     if (appBase == stripHash(url)) {
10834       rewrittenUrl = url;
10835     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
10836       rewrittenUrl = appBase + hashPrefix + appUrl;
10837     } else if (appBaseNoFile === url + '/') {
10838       rewrittenUrl = appBaseNoFile;
10839     }
10840     if (rewrittenUrl) {
10841       this.$$parse(rewrittenUrl);
10842     }
10843     return !!rewrittenUrl;
10844   };
10845
10846   this.$$compose = function() {
10847     var search = toKeyValue(this.$$search),
10848         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10849
10850     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10851     // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
10852     this.$$absUrl = appBase + hashPrefix + this.$$url;
10853   };
10854
10855 }
10856
10857
10858 var locationPrototype = {
10859
10860   /**
10861    * Are we in html5 mode?
10862    * @private
10863    */
10864   $$html5: false,
10865
10866   /**
10867    * Has any change been replacing?
10868    * @private
10869    */
10870   $$replace: false,
10871
10872   /**
10873    * @ngdoc method
10874    * @name $location#absUrl
10875    *
10876    * @description
10877    * This method is getter only.
10878    *
10879    * Return full url representation with all segments encoded according to rules specified in
10880    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
10881    *
10882    *
10883    * ```js
10884    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10885    * var absUrl = $location.absUrl();
10886    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
10887    * ```
10888    *
10889    * @return {string} full url
10890    */
10891   absUrl: locationGetter('$$absUrl'),
10892
10893   /**
10894    * @ngdoc method
10895    * @name $location#url
10896    *
10897    * @description
10898    * This method is getter / setter.
10899    *
10900    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
10901    *
10902    * Change path, search and hash, when called with parameter and return `$location`.
10903    *
10904    *
10905    * ```js
10906    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10907    * var url = $location.url();
10908    * // => "/some/path?foo=bar&baz=xoxo"
10909    * ```
10910    *
10911    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
10912    * @return {string} url
10913    */
10914   url: function(url) {
10915     if (isUndefined(url))
10916       return this.$$url;
10917
10918     var match = PATH_MATCH.exec(url);
10919     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
10920     if (match[2] || match[1] || url === '') this.search(match[3] || '');
10921     this.hash(match[5] || '');
10922
10923     return this;
10924   },
10925
10926   /**
10927    * @ngdoc method
10928    * @name $location#protocol
10929    *
10930    * @description
10931    * This method is getter only.
10932    *
10933    * Return protocol of current url.
10934    *
10935    *
10936    * ```js
10937    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10938    * var protocol = $location.protocol();
10939    * // => "http"
10940    * ```
10941    *
10942    * @return {string} protocol of current url
10943    */
10944   protocol: locationGetter('$$protocol'),
10945
10946   /**
10947    * @ngdoc method
10948    * @name $location#host
10949    *
10950    * @description
10951    * This method is getter only.
10952    *
10953    * Return host of current url.
10954    *
10955    *
10956    * ```js
10957    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10958    * var host = $location.host();
10959    * // => "example.com"
10960    * ```
10961    *
10962    * @return {string} host of current url.
10963    */
10964   host: locationGetter('$$host'),
10965
10966   /**
10967    * @ngdoc method
10968    * @name $location#port
10969    *
10970    * @description
10971    * This method is getter only.
10972    *
10973    * Return port of current url.
10974    *
10975    *
10976    * ```js
10977    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10978    * var port = $location.port();
10979    * // => 80
10980    * ```
10981    *
10982    * @return {Number} port
10983    */
10984   port: locationGetter('$$port'),
10985
10986   /**
10987    * @ngdoc method
10988    * @name $location#path
10989    *
10990    * @description
10991    * This method is getter / setter.
10992    *
10993    * Return path of current url when called without any parameter.
10994    *
10995    * Change path when called with parameter and return `$location`.
10996    *
10997    * Note: Path should always begin with forward slash (/), this method will add the forward slash
10998    * if it is missing.
10999    *
11000    *
11001    * ```js
11002    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11003    * var path = $location.path();
11004    * // => "/some/path"
11005    * ```
11006    *
11007    * @param {(string|number)=} path New path
11008    * @return {string} path
11009    */
11010   path: locationGetterSetter('$$path', function(path) {
11011     path = path !== null ? path.toString() : '';
11012     return path.charAt(0) == '/' ? path : '/' + path;
11013   }),
11014
11015   /**
11016    * @ngdoc method
11017    * @name $location#search
11018    *
11019    * @description
11020    * This method is getter / setter.
11021    *
11022    * Return search part (as object) of current url when called without any parameter.
11023    *
11024    * Change search part when called with parameter and return `$location`.
11025    *
11026    *
11027    * ```js
11028    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11029    * var searchObject = $location.search();
11030    * // => {foo: 'bar', baz: 'xoxo'}
11031    *
11032    * // set foo to 'yipee'
11033    * $location.search('foo', 'yipee');
11034    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11035    * ```
11036    *
11037    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11038    * hash object.
11039    *
11040    * When called with a single argument the method acts as a setter, setting the `search` component
11041    * of `$location` to the specified value.
11042    *
11043    * If the argument is a hash object containing an array of values, these values will be encoded
11044    * as duplicate search parameters in the url.
11045    *
11046    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11047    * will override only a single search property.
11048    *
11049    * If `paramValue` is an array, it will override the property of the `search` component of
11050    * `$location` specified via the first argument.
11051    *
11052    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11053    *
11054    * If `paramValue` is `true`, the property specified via the first argument will be added with no
11055    * value nor trailing equal sign.
11056    *
11057    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11058    * one or more arguments returns `$location` object itself.
11059    */
11060   search: function(search, paramValue) {
11061     switch (arguments.length) {
11062       case 0:
11063         return this.$$search;
11064       case 1:
11065         if (isString(search) || isNumber(search)) {
11066           search = search.toString();
11067           this.$$search = parseKeyValue(search);
11068         } else if (isObject(search)) {
11069           search = copy(search, {});
11070           // remove object undefined or null properties
11071           forEach(search, function(value, key) {
11072             if (value == null) delete search[key];
11073           });
11074
11075           this.$$search = search;
11076         } else {
11077           throw $locationMinErr('isrcharg',
11078               'The first argument of the `$location#search()` call must be a string or an object.');
11079         }
11080         break;
11081       default:
11082         if (isUndefined(paramValue) || paramValue === null) {
11083           delete this.$$search[search];
11084         } else {
11085           this.$$search[search] = paramValue;
11086         }
11087     }
11088
11089     this.$$compose();
11090     return this;
11091   },
11092
11093   /**
11094    * @ngdoc method
11095    * @name $location#hash
11096    *
11097    * @description
11098    * This method is getter / setter.
11099    *
11100    * Return hash fragment when called without any parameter.
11101    *
11102    * Change hash fragment when called with parameter and return `$location`.
11103    *
11104    *
11105    * ```js
11106    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
11107    * var hash = $location.hash();
11108    * // => "hashValue"
11109    * ```
11110    *
11111    * @param {(string|number)=} hash New hash fragment
11112    * @return {string} hash
11113    */
11114   hash: locationGetterSetter('$$hash', function(hash) {
11115     return hash !== null ? hash.toString() : '';
11116   }),
11117
11118   /**
11119    * @ngdoc method
11120    * @name $location#replace
11121    *
11122    * @description
11123    * If called, all changes to $location during current `$digest` will be replacing current history
11124    * record, instead of adding new one.
11125    */
11126   replace: function() {
11127     this.$$replace = true;
11128     return this;
11129   }
11130 };
11131
11132 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
11133   Location.prototype = Object.create(locationPrototype);
11134
11135   /**
11136    * @ngdoc method
11137    * @name $location#state
11138    *
11139    * @description
11140    * This method is getter / setter.
11141    *
11142    * Return the history state object when called without any parameter.
11143    *
11144    * Change the history state object when called with one parameter and return `$location`.
11145    * The state object is later passed to `pushState` or `replaceState`.
11146    *
11147    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
11148    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
11149    * older browsers (like IE9 or Android < 4.0), don't use this method.
11150    *
11151    * @param {object=} state State object for pushState or replaceState
11152    * @return {object} state
11153    */
11154   Location.prototype.state = function(state) {
11155     if (!arguments.length)
11156       return this.$$state;
11157
11158     if (Location !== LocationHtml5Url || !this.$$html5) {
11159       throw $locationMinErr('nostate', 'History API state support is available only ' +
11160         'in HTML5 mode and only in browsers supporting HTML5 History API');
11161     }
11162     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
11163     // but we're changing the $$state reference to $browser.state() during the $digest
11164     // so the modification window is narrow.
11165     this.$$state = isUndefined(state) ? null : state;
11166
11167     return this;
11168   };
11169 });
11170
11171
11172 function locationGetter(property) {
11173   return function() {
11174     return this[property];
11175   };
11176 }
11177
11178
11179 function locationGetterSetter(property, preprocess) {
11180   return function(value) {
11181     if (isUndefined(value))
11182       return this[property];
11183
11184     this[property] = preprocess(value);
11185     this.$$compose();
11186
11187     return this;
11188   };
11189 }
11190
11191
11192 /**
11193  * @ngdoc service
11194  * @name $location
11195  *
11196  * @requires $rootElement
11197  *
11198  * @description
11199  * The $location service parses the URL in the browser address bar (based on the
11200  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
11201  * available to your application. Changes to the URL in the address bar are reflected into
11202  * $location service and changes to $location are reflected into the browser address bar.
11203  *
11204  * **The $location service:**
11205  *
11206  * - Exposes the current URL in the browser address bar, so you can
11207  *   - Watch and observe the URL.
11208  *   - Change the URL.
11209  * - Synchronizes the URL with the browser when the user
11210  *   - Changes the address bar.
11211  *   - Clicks the back or forward button (or clicks a History link).
11212  *   - Clicks on a link.
11213  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
11214  *
11215  * For more information see {@link guide/$location Developer Guide: Using $location}
11216  */
11217
11218 /**
11219  * @ngdoc provider
11220  * @name $locationProvider
11221  * @description
11222  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
11223  */
11224 function $LocationProvider() {
11225   var hashPrefix = '',
11226       html5Mode = {
11227         enabled: false,
11228         requireBase: true,
11229         rewriteLinks: true
11230       };
11231
11232   /**
11233    * @ngdoc method
11234    * @name $locationProvider#hashPrefix
11235    * @description
11236    * @param {string=} prefix Prefix for hash part (containing path and search)
11237    * @returns {*} current value if used as getter or itself (chaining) if used as setter
11238    */
11239   this.hashPrefix = function(prefix) {
11240     if (isDefined(prefix)) {
11241       hashPrefix = prefix;
11242       return this;
11243     } else {
11244       return hashPrefix;
11245     }
11246   };
11247
11248   /**
11249    * @ngdoc method
11250    * @name $locationProvider#html5Mode
11251    * @description
11252    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
11253    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
11254    *   properties:
11255    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
11256    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
11257    *     support `pushState`.
11258    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
11259    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
11260    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
11261    *     See the {@link guide/$location $location guide for more information}
11262    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
11263    *     enables/disables url rewriting for relative links.
11264    *
11265    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
11266    */
11267   this.html5Mode = function(mode) {
11268     if (isBoolean(mode)) {
11269       html5Mode.enabled = mode;
11270       return this;
11271     } else if (isObject(mode)) {
11272
11273       if (isBoolean(mode.enabled)) {
11274         html5Mode.enabled = mode.enabled;
11275       }
11276
11277       if (isBoolean(mode.requireBase)) {
11278         html5Mode.requireBase = mode.requireBase;
11279       }
11280
11281       if (isBoolean(mode.rewriteLinks)) {
11282         html5Mode.rewriteLinks = mode.rewriteLinks;
11283       }
11284
11285       return this;
11286     } else {
11287       return html5Mode;
11288     }
11289   };
11290
11291   /**
11292    * @ngdoc event
11293    * @name $location#$locationChangeStart
11294    * @eventType broadcast on root scope
11295    * @description
11296    * Broadcasted before a URL will change.
11297    *
11298    * This change can be prevented by calling
11299    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
11300    * details about event object. Upon successful change
11301    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
11302    *
11303    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11304    * the browser supports the HTML5 History API.
11305    *
11306    * @param {Object} angularEvent Synthetic event object.
11307    * @param {string} newUrl New URL
11308    * @param {string=} oldUrl URL that was before it was changed.
11309    * @param {string=} newState New history state object
11310    * @param {string=} oldState History state object that was before it was changed.
11311    */
11312
11313   /**
11314    * @ngdoc event
11315    * @name $location#$locationChangeSuccess
11316    * @eventType broadcast on root scope
11317    * @description
11318    * Broadcasted after a URL was changed.
11319    *
11320    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11321    * the browser supports the HTML5 History API.
11322    *
11323    * @param {Object} angularEvent Synthetic event object.
11324    * @param {string} newUrl New URL
11325    * @param {string=} oldUrl URL that was before it was changed.
11326    * @param {string=} newState New history state object
11327    * @param {string=} oldState History state object that was before it was changed.
11328    */
11329
11330   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
11331       function($rootScope, $browser, $sniffer, $rootElement, $window) {
11332     var $location,
11333         LocationMode,
11334         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
11335         initialUrl = $browser.url(),
11336         appBase;
11337
11338     if (html5Mode.enabled) {
11339       if (!baseHref && html5Mode.requireBase) {
11340         throw $locationMinErr('nobase',
11341           "$location in HTML5 mode requires a <base> tag to be present!");
11342       }
11343       appBase = serverBase(initialUrl) + (baseHref || '/');
11344       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
11345     } else {
11346       appBase = stripHash(initialUrl);
11347       LocationMode = LocationHashbangUrl;
11348     }
11349     $location = new LocationMode(appBase, '#' + hashPrefix);
11350     $location.$$parseLinkUrl(initialUrl, initialUrl);
11351
11352     $location.$$state = $browser.state();
11353
11354     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
11355
11356     function setBrowserUrlWithFallback(url, replace, state) {
11357       var oldUrl = $location.url();
11358       var oldState = $location.$$state;
11359       try {
11360         $browser.url(url, replace, state);
11361
11362         // Make sure $location.state() returns referentially identical (not just deeply equal)
11363         // state object; this makes possible quick checking if the state changed in the digest
11364         // loop. Checking deep equality would be too expensive.
11365         $location.$$state = $browser.state();
11366       } catch (e) {
11367         // Restore old values if pushState fails
11368         $location.url(oldUrl);
11369         $location.$$state = oldState;
11370
11371         throw e;
11372       }
11373     }
11374
11375     $rootElement.on('click', function(event) {
11376       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
11377       // currently we open nice url link and redirect then
11378
11379       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
11380
11381       var elm = jqLite(event.target);
11382
11383       // traverse the DOM up to find first A tag
11384       while (nodeName_(elm[0]) !== 'a') {
11385         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
11386         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
11387       }
11388
11389       var absHref = elm.prop('href');
11390       // get the actual href attribute - see
11391       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
11392       var relHref = elm.attr('href') || elm.attr('xlink:href');
11393
11394       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
11395         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
11396         // an animation.
11397         absHref = urlResolve(absHref.animVal).href;
11398       }
11399
11400       // Ignore when url is started with javascript: or mailto:
11401       if (IGNORE_URI_REGEXP.test(absHref)) return;
11402
11403       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
11404         if ($location.$$parseLinkUrl(absHref, relHref)) {
11405           // We do a preventDefault for all urls that are part of the angular application,
11406           // in html5mode and also without, so that we are able to abort navigation without
11407           // getting double entries in the location history.
11408           event.preventDefault();
11409           // update location manually
11410           if ($location.absUrl() != $browser.url()) {
11411             $rootScope.$apply();
11412             // hack to work around FF6 bug 684208 when scenario runner clicks on links
11413             $window.angular['ff-684208-preventDefault'] = true;
11414           }
11415         }
11416       }
11417     });
11418
11419
11420     // rewrite hashbang url <> html5 url
11421     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
11422       $browser.url($location.absUrl(), true);
11423     }
11424
11425     var initializing = true;
11426
11427     // update $location when $browser url changes
11428     $browser.onUrlChange(function(newUrl, newState) {
11429       $rootScope.$evalAsync(function() {
11430         var oldUrl = $location.absUrl();
11431         var oldState = $location.$$state;
11432         var defaultPrevented;
11433
11434         $location.$$parse(newUrl);
11435         $location.$$state = newState;
11436
11437         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11438             newState, oldState).defaultPrevented;
11439
11440         // if the location was changed by a `$locationChangeStart` handler then stop
11441         // processing this location change
11442         if ($location.absUrl() !== newUrl) return;
11443
11444         if (defaultPrevented) {
11445           $location.$$parse(oldUrl);
11446           $location.$$state = oldState;
11447           setBrowserUrlWithFallback(oldUrl, false, oldState);
11448         } else {
11449           initializing = false;
11450           afterLocationChange(oldUrl, oldState);
11451         }
11452       });
11453       if (!$rootScope.$$phase) $rootScope.$digest();
11454     });
11455
11456     // update browser
11457     $rootScope.$watch(function $locationWatch() {
11458       var oldUrl = trimEmptyHash($browser.url());
11459       var newUrl = trimEmptyHash($location.absUrl());
11460       var oldState = $browser.state();
11461       var currentReplace = $location.$$replace;
11462       var urlOrStateChanged = oldUrl !== newUrl ||
11463         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
11464
11465       if (initializing || urlOrStateChanged) {
11466         initializing = false;
11467
11468         $rootScope.$evalAsync(function() {
11469           var newUrl = $location.absUrl();
11470           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11471               $location.$$state, oldState).defaultPrevented;
11472
11473           // if the location was changed by a `$locationChangeStart` handler then stop
11474           // processing this location change
11475           if ($location.absUrl() !== newUrl) return;
11476
11477           if (defaultPrevented) {
11478             $location.$$parse(oldUrl);
11479             $location.$$state = oldState;
11480           } else {
11481             if (urlOrStateChanged) {
11482               setBrowserUrlWithFallback(newUrl, currentReplace,
11483                                         oldState === $location.$$state ? null : $location.$$state);
11484             }
11485             afterLocationChange(oldUrl, oldState);
11486           }
11487         });
11488       }
11489
11490       $location.$$replace = false;
11491
11492       // we don't need to return anything because $evalAsync will make the digest loop dirty when
11493       // there is a change
11494     });
11495
11496     return $location;
11497
11498     function afterLocationChange(oldUrl, oldState) {
11499       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
11500         $location.$$state, oldState);
11501     }
11502 }];
11503 }
11504
11505 /**
11506  * @ngdoc service
11507  * @name $log
11508  * @requires $window
11509  *
11510  * @description
11511  * Simple service for logging. Default implementation safely writes the message
11512  * into the browser's console (if present).
11513  *
11514  * The main purpose of this service is to simplify debugging and troubleshooting.
11515  *
11516  * The default is to log `debug` messages. You can use
11517  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
11518  *
11519  * @example
11520    <example module="logExample">
11521      <file name="script.js">
11522        angular.module('logExample', [])
11523          .controller('LogController', ['$scope', '$log', function($scope, $log) {
11524            $scope.$log = $log;
11525            $scope.message = 'Hello World!';
11526          }]);
11527      </file>
11528      <file name="index.html">
11529        <div ng-controller="LogController">
11530          <p>Reload this page with open console, enter text and hit the log button...</p>
11531          Message:
11532          <input type="text" ng-model="message"/>
11533          <button ng-click="$log.log(message)">log</button>
11534          <button ng-click="$log.warn(message)">warn</button>
11535          <button ng-click="$log.info(message)">info</button>
11536          <button ng-click="$log.error(message)">error</button>
11537          <button ng-click="$log.debug(message)">debug</button>
11538        </div>
11539      </file>
11540    </example>
11541  */
11542
11543 /**
11544  * @ngdoc provider
11545  * @name $logProvider
11546  * @description
11547  * Use the `$logProvider` to configure how the application logs messages
11548  */
11549 function $LogProvider() {
11550   var debug = true,
11551       self = this;
11552
11553   /**
11554    * @ngdoc method
11555    * @name $logProvider#debugEnabled
11556    * @description
11557    * @param {boolean=} flag enable or disable debug level messages
11558    * @returns {*} current value if used as getter or itself (chaining) if used as setter
11559    */
11560   this.debugEnabled = function(flag) {
11561     if (isDefined(flag)) {
11562       debug = flag;
11563     return this;
11564     } else {
11565       return debug;
11566     }
11567   };
11568
11569   this.$get = ['$window', function($window) {
11570     return {
11571       /**
11572        * @ngdoc method
11573        * @name $log#log
11574        *
11575        * @description
11576        * Write a log message
11577        */
11578       log: consoleLog('log'),
11579
11580       /**
11581        * @ngdoc method
11582        * @name $log#info
11583        *
11584        * @description
11585        * Write an information message
11586        */
11587       info: consoleLog('info'),
11588
11589       /**
11590        * @ngdoc method
11591        * @name $log#warn
11592        *
11593        * @description
11594        * Write a warning message
11595        */
11596       warn: consoleLog('warn'),
11597
11598       /**
11599        * @ngdoc method
11600        * @name $log#error
11601        *
11602        * @description
11603        * Write an error message
11604        */
11605       error: consoleLog('error'),
11606
11607       /**
11608        * @ngdoc method
11609        * @name $log#debug
11610        *
11611        * @description
11612        * Write a debug message
11613        */
11614       debug: (function() {
11615         var fn = consoleLog('debug');
11616
11617         return function() {
11618           if (debug) {
11619             fn.apply(self, arguments);
11620           }
11621         };
11622       }())
11623     };
11624
11625     function formatError(arg) {
11626       if (arg instanceof Error) {
11627         if (arg.stack) {
11628           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
11629               ? 'Error: ' + arg.message + '\n' + arg.stack
11630               : arg.stack;
11631         } else if (arg.sourceURL) {
11632           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
11633         }
11634       }
11635       return arg;
11636     }
11637
11638     function consoleLog(type) {
11639       var console = $window.console || {},
11640           logFn = console[type] || console.log || noop,
11641           hasApply = false;
11642
11643       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
11644       // The reason behind this is that console.log has type "object" in IE8...
11645       try {
11646         hasApply = !!logFn.apply;
11647       } catch (e) {}
11648
11649       if (hasApply) {
11650         return function() {
11651           var args = [];
11652           forEach(arguments, function(arg) {
11653             args.push(formatError(arg));
11654           });
11655           return logFn.apply(console, args);
11656         };
11657       }
11658
11659       // we are IE which either doesn't have window.console => this is noop and we do nothing,
11660       // or we are IE where console.log doesn't have apply so we log at least first 2 args
11661       return function(arg1, arg2) {
11662         logFn(arg1, arg2 == null ? '' : arg2);
11663       };
11664     }
11665   }];
11666 }
11667
11668 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11669  *     Any commits to this file should be reviewed with security in mind.  *
11670  *   Changes to this file can potentially create security vulnerabilities. *
11671  *          An approval from 2 Core members with history of modifying      *
11672  *                         this file is required.                          *
11673  *                                                                         *
11674  *  Does the change somehow allow for arbitrary javascript to be executed? *
11675  *    Or allows for someone to change the prototype of built-in objects?   *
11676  *     Or gives undesired access to variables likes document or window?    *
11677  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11678
11679 var $parseMinErr = minErr('$parse');
11680
11681 // Sandboxing Angular Expressions
11682 // ------------------------------
11683 // Angular expressions are generally considered safe because these expressions only have direct
11684 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
11685 // obtaining a reference to native JS functions such as the Function constructor.
11686 //
11687 // As an example, consider the following Angular expression:
11688 //
11689 //   {}.toString.constructor('alert("evil JS code")')
11690 //
11691 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
11692 // against the expression language, but not to prevent exploits that were enabled by exposing
11693 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
11694 // practice and therefore we are not even trying to protect against interaction with an object
11695 // explicitly exposed in this way.
11696 //
11697 // In general, it is not possible to access a Window object from an angular expression unless a
11698 // window or some DOM object that has a reference to window is published onto a Scope.
11699 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
11700 // native objects.
11701 //
11702 // See https://docs.angularjs.org/guide/security
11703
11704
11705 function ensureSafeMemberName(name, fullExpression) {
11706   if (name === "__defineGetter__" || name === "__defineSetter__"
11707       || name === "__lookupGetter__" || name === "__lookupSetter__"
11708       || name === "__proto__") {
11709     throw $parseMinErr('isecfld',
11710         'Attempting to access a disallowed field in Angular expressions! '
11711         + 'Expression: {0}', fullExpression);
11712   }
11713   return name;
11714 }
11715
11716 function ensureSafeObject(obj, fullExpression) {
11717   // nifty check if obj is Function that is fast and works across iframes and other contexts
11718   if (obj) {
11719     if (obj.constructor === obj) {
11720       throw $parseMinErr('isecfn',
11721           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11722           fullExpression);
11723     } else if (// isWindow(obj)
11724         obj.window === obj) {
11725       throw $parseMinErr('isecwindow',
11726           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
11727           fullExpression);
11728     } else if (// isElement(obj)
11729         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
11730       throw $parseMinErr('isecdom',
11731           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
11732           fullExpression);
11733     } else if (// block Object so that we can't get hold of dangerous Object.* methods
11734         obj === Object) {
11735       throw $parseMinErr('isecobj',
11736           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
11737           fullExpression);
11738     }
11739   }
11740   return obj;
11741 }
11742
11743 var CALL = Function.prototype.call;
11744 var APPLY = Function.prototype.apply;
11745 var BIND = Function.prototype.bind;
11746
11747 function ensureSafeFunction(obj, fullExpression) {
11748   if (obj) {
11749     if (obj.constructor === obj) {
11750       throw $parseMinErr('isecfn',
11751         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11752         fullExpression);
11753     } else if (obj === CALL || obj === APPLY || obj === BIND) {
11754       throw $parseMinErr('isecff',
11755         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
11756         fullExpression);
11757     }
11758   }
11759 }
11760
11761 //Keyword constants
11762 var CONSTANTS = createMap();
11763 forEach({
11764   'null': function() { return null; },
11765   'true': function() { return true; },
11766   'false': function() { return false; },
11767   'undefined': function() {}
11768 }, function(constantGetter, name) {
11769   constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true;
11770   CONSTANTS[name] = constantGetter;
11771 });
11772
11773 //Not quite a constant, but can be lex/parsed the same
11774 CONSTANTS['this'] = function(self) { return self; };
11775 CONSTANTS['this'].sharedGetter = true;
11776
11777
11778 //Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
11779 var OPERATORS = extend(createMap(), {
11780     '+':function(self, locals, a, b) {
11781       a=a(self, locals); b=b(self, locals);
11782       if (isDefined(a)) {
11783         if (isDefined(b)) {
11784           return a + b;
11785         }
11786         return a;
11787       }
11788       return isDefined(b) ? b : undefined;},
11789     '-':function(self, locals, a, b) {
11790           a=a(self, locals); b=b(self, locals);
11791           return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
11792         },
11793     '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
11794     '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
11795     '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
11796     '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
11797     '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
11798     '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
11799     '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
11800     '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
11801     '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
11802     '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
11803     '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
11804     '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
11805     '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
11806     '!':function(self, locals, a) {return !a(self, locals);},
11807
11808     //Tokenized as operators but parsed as assignment/filters
11809     '=':true,
11810     '|':true
11811 });
11812 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
11813
11814
11815 /////////////////////////////////////////
11816
11817
11818 /**
11819  * @constructor
11820  */
11821 var Lexer = function(options) {
11822   this.options = options;
11823 };
11824
11825 Lexer.prototype = {
11826   constructor: Lexer,
11827
11828   lex: function(text) {
11829     this.text = text;
11830     this.index = 0;
11831     this.tokens = [];
11832
11833     while (this.index < this.text.length) {
11834       var ch = this.text.charAt(this.index);
11835       if (ch === '"' || ch === "'") {
11836         this.readString(ch);
11837       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
11838         this.readNumber();
11839       } else if (this.isIdent(ch)) {
11840         this.readIdent();
11841       } else if (this.is(ch, '(){}[].,;:?')) {
11842         this.tokens.push({index: this.index, text: ch});
11843         this.index++;
11844       } else if (this.isWhitespace(ch)) {
11845         this.index++;
11846       } else {
11847         var ch2 = ch + this.peek();
11848         var ch3 = ch2 + this.peek(2);
11849         var op1 = OPERATORS[ch];
11850         var op2 = OPERATORS[ch2];
11851         var op3 = OPERATORS[ch3];
11852         if (op1 || op2 || op3) {
11853           var token = op3 ? ch3 : (op2 ? ch2 : ch);
11854           this.tokens.push({index: this.index, text: token, operator: true});
11855           this.index += token.length;
11856         } else {
11857           this.throwError('Unexpected next character ', this.index, this.index + 1);
11858         }
11859       }
11860     }
11861     return this.tokens;
11862   },
11863
11864   is: function(ch, chars) {
11865     return chars.indexOf(ch) !== -1;
11866   },
11867
11868   peek: function(i) {
11869     var num = i || 1;
11870     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
11871   },
11872
11873   isNumber: function(ch) {
11874     return ('0' <= ch && ch <= '9') && typeof ch === "string";
11875   },
11876
11877   isWhitespace: function(ch) {
11878     // IE treats non-breaking space as \u00A0
11879     return (ch === ' ' || ch === '\r' || ch === '\t' ||
11880             ch === '\n' || ch === '\v' || ch === '\u00A0');
11881   },
11882
11883   isIdent: function(ch) {
11884     return ('a' <= ch && ch <= 'z' ||
11885             'A' <= ch && ch <= 'Z' ||
11886             '_' === ch || ch === '$');
11887   },
11888
11889   isExpOperator: function(ch) {
11890     return (ch === '-' || ch === '+' || this.isNumber(ch));
11891   },
11892
11893   throwError: function(error, start, end) {
11894     end = end || this.index;
11895     var colStr = (isDefined(start)
11896             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
11897             : ' ' + end);
11898     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
11899         error, colStr, this.text);
11900   },
11901
11902   readNumber: function() {
11903     var number = '';
11904     var start = this.index;
11905     while (this.index < this.text.length) {
11906       var ch = lowercase(this.text.charAt(this.index));
11907       if (ch == '.' || this.isNumber(ch)) {
11908         number += ch;
11909       } else {
11910         var peekCh = this.peek();
11911         if (ch == 'e' && this.isExpOperator(peekCh)) {
11912           number += ch;
11913         } else if (this.isExpOperator(ch) &&
11914             peekCh && this.isNumber(peekCh) &&
11915             number.charAt(number.length - 1) == 'e') {
11916           number += ch;
11917         } else if (this.isExpOperator(ch) &&
11918             (!peekCh || !this.isNumber(peekCh)) &&
11919             number.charAt(number.length - 1) == 'e') {
11920           this.throwError('Invalid exponent');
11921         } else {
11922           break;
11923         }
11924       }
11925       this.index++;
11926     }
11927     this.tokens.push({
11928       index: start,
11929       text: number,
11930       constant: true,
11931       value: Number(number)
11932     });
11933   },
11934
11935   readIdent: function() {
11936     var start = this.index;
11937     while (this.index < this.text.length) {
11938       var ch = this.text.charAt(this.index);
11939       if (!(this.isIdent(ch) || this.isNumber(ch))) {
11940         break;
11941       }
11942       this.index++;
11943     }
11944     this.tokens.push({
11945       index: start,
11946       text: this.text.slice(start, this.index),
11947       identifier: true
11948     });
11949   },
11950
11951   readString: function(quote) {
11952     var start = this.index;
11953     this.index++;
11954     var string = '';
11955     var rawString = quote;
11956     var escape = false;
11957     while (this.index < this.text.length) {
11958       var ch = this.text.charAt(this.index);
11959       rawString += ch;
11960       if (escape) {
11961         if (ch === 'u') {
11962           var hex = this.text.substring(this.index + 1, this.index + 5);
11963           if (!hex.match(/[\da-f]{4}/i))
11964             this.throwError('Invalid unicode escape [\\u' + hex + ']');
11965           this.index += 4;
11966           string += String.fromCharCode(parseInt(hex, 16));
11967         } else {
11968           var rep = ESCAPE[ch];
11969           string = string + (rep || ch);
11970         }
11971         escape = false;
11972       } else if (ch === '\\') {
11973         escape = true;
11974       } else if (ch === quote) {
11975         this.index++;
11976         this.tokens.push({
11977           index: start,
11978           text: rawString,
11979           constant: true,
11980           value: string
11981         });
11982         return;
11983       } else {
11984         string += ch;
11985       }
11986       this.index++;
11987     }
11988     this.throwError('Unterminated quote', start);
11989   }
11990 };
11991
11992
11993 function isConstant(exp) {
11994   return exp.constant;
11995 }
11996
11997 /**
11998  * @constructor
11999  */
12000 var Parser = function(lexer, $filter, options) {
12001   this.lexer = lexer;
12002   this.$filter = $filter;
12003   this.options = options;
12004 };
12005
12006 Parser.ZERO = extend(function() {
12007   return 0;
12008 }, {
12009   sharedGetter: true,
12010   constant: true
12011 });
12012
12013 Parser.prototype = {
12014   constructor: Parser,
12015
12016   parse: function(text) {
12017     this.text = text;
12018     this.tokens = this.lexer.lex(text);
12019
12020     var value = this.statements();
12021
12022     if (this.tokens.length !== 0) {
12023       this.throwError('is an unexpected token', this.tokens[0]);
12024     }
12025
12026     value.literal = !!value.literal;
12027     value.constant = !!value.constant;
12028
12029     return value;
12030   },
12031
12032   primary: function() {
12033     var primary;
12034     if (this.expect('(')) {
12035       primary = this.filterChain();
12036       this.consume(')');
12037     } else if (this.expect('[')) {
12038       primary = this.arrayDeclaration();
12039     } else if (this.expect('{')) {
12040       primary = this.object();
12041     } else if (this.peek().identifier && this.peek().text in CONSTANTS) {
12042       primary = CONSTANTS[this.consume().text];
12043     } else if (this.peek().identifier) {
12044       primary = this.identifier();
12045     } else if (this.peek().constant) {
12046       primary = this.constant();
12047     } else {
12048       this.throwError('not a primary expression', this.peek());
12049     }
12050
12051     var next, context;
12052     while ((next = this.expect('(', '[', '.'))) {
12053       if (next.text === '(') {
12054         primary = this.functionCall(primary, context);
12055         context = null;
12056       } else if (next.text === '[') {
12057         context = primary;
12058         primary = this.objectIndex(primary);
12059       } else if (next.text === '.') {
12060         context = primary;
12061         primary = this.fieldAccess(primary);
12062       } else {
12063         this.throwError('IMPOSSIBLE');
12064       }
12065     }
12066     return primary;
12067   },
12068
12069   throwError: function(msg, token) {
12070     throw $parseMinErr('syntax',
12071         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
12072           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
12073   },
12074
12075   peekToken: function() {
12076     if (this.tokens.length === 0)
12077       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12078     return this.tokens[0];
12079   },
12080
12081   peek: function(e1, e2, e3, e4) {
12082     return this.peekAhead(0, e1, e2, e3, e4);
12083   },
12084   peekAhead: function(i, e1, e2, e3, e4) {
12085     if (this.tokens.length > i) {
12086       var token = this.tokens[i];
12087       var t = token.text;
12088       if (t === e1 || t === e2 || t === e3 || t === e4 ||
12089           (!e1 && !e2 && !e3 && !e4)) {
12090         return token;
12091       }
12092     }
12093     return false;
12094   },
12095
12096   expect: function(e1, e2, e3, e4) {
12097     var token = this.peek(e1, e2, e3, e4);
12098     if (token) {
12099       this.tokens.shift();
12100       return token;
12101     }
12102     return false;
12103   },
12104
12105   consume: function(e1) {
12106     if (this.tokens.length === 0) {
12107       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12108     }
12109
12110     var token = this.expect(e1);
12111     if (!token) {
12112       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
12113     }
12114     return token;
12115   },
12116
12117   unaryFn: function(op, right) {
12118     var fn = OPERATORS[op];
12119     return extend(function $parseUnaryFn(self, locals) {
12120       return fn(self, locals, right);
12121     }, {
12122       constant:right.constant,
12123       inputs: [right]
12124     });
12125   },
12126
12127   binaryFn: function(left, op, right, isBranching) {
12128     var fn = OPERATORS[op];
12129     return extend(function $parseBinaryFn(self, locals) {
12130       return fn(self, locals, left, right);
12131     }, {
12132       constant: left.constant && right.constant,
12133       inputs: !isBranching && [left, right]
12134     });
12135   },
12136
12137   identifier: function() {
12138     var id = this.consume().text;
12139
12140     //Continue reading each `.identifier` unless it is a method invocation
12141     while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
12142       id += this.consume().text + this.consume().text;
12143     }
12144
12145     return getterFn(id, this.options, this.text);
12146   },
12147
12148   constant: function() {
12149     var value = this.consume().value;
12150
12151     return extend(function $parseConstant() {
12152       return value;
12153     }, {
12154       constant: true,
12155       literal: true
12156     });
12157   },
12158
12159   statements: function() {
12160     var statements = [];
12161     while (true) {
12162       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12163         statements.push(this.filterChain());
12164       if (!this.expect(';')) {
12165         // optimize for the common case where there is only one statement.
12166         // TODO(size): maybe we should not support multiple statements?
12167         return (statements.length === 1)
12168             ? statements[0]
12169             : function $parseStatements(self, locals) {
12170                 var value;
12171                 for (var i = 0, ii = statements.length; i < ii; i++) {
12172                   value = statements[i](self, locals);
12173                 }
12174                 return value;
12175               };
12176       }
12177     }
12178   },
12179
12180   filterChain: function() {
12181     var left = this.expression();
12182     var token;
12183     while ((token = this.expect('|'))) {
12184       left = this.filter(left);
12185     }
12186     return left;
12187   },
12188
12189   filter: function(inputFn) {
12190     var fn = this.$filter(this.consume().text);
12191     var argsFn;
12192     var args;
12193
12194     if (this.peek(':')) {
12195       argsFn = [];
12196       args = []; // we can safely reuse the array
12197       while (this.expect(':')) {
12198         argsFn.push(this.expression());
12199       }
12200     }
12201
12202     var inputs = [inputFn].concat(argsFn || []);
12203
12204     return extend(function $parseFilter(self, locals) {
12205       var input = inputFn(self, locals);
12206       if (args) {
12207         args[0] = input;
12208
12209         var i = argsFn.length;
12210         while (i--) {
12211           args[i + 1] = argsFn[i](self, locals);
12212         }
12213
12214         return fn.apply(undefined, args);
12215       }
12216
12217       return fn(input);
12218     }, {
12219       constant: !fn.$stateful && inputs.every(isConstant),
12220       inputs: !fn.$stateful && inputs
12221     });
12222   },
12223
12224   expression: function() {
12225     return this.assignment();
12226   },
12227
12228   assignment: function() {
12229     var left = this.ternary();
12230     var right;
12231     var token;
12232     if ((token = this.expect('='))) {
12233       if (!left.assign) {
12234         this.throwError('implies assignment but [' +
12235             this.text.substring(0, token.index) + '] can not be assigned to', token);
12236       }
12237       right = this.ternary();
12238       return extend(function $parseAssignment(scope, locals) {
12239         return left.assign(scope, right(scope, locals), locals);
12240       }, {
12241         inputs: [left, right]
12242       });
12243     }
12244     return left;
12245   },
12246
12247   ternary: function() {
12248     var left = this.logicalOR();
12249     var middle;
12250     var token;
12251     if ((token = this.expect('?'))) {
12252       middle = this.assignment();
12253       if (this.consume(':')) {
12254         var right = this.assignment();
12255
12256         return extend(function $parseTernary(self, locals) {
12257           return left(self, locals) ? middle(self, locals) : right(self, locals);
12258         }, {
12259           constant: left.constant && middle.constant && right.constant
12260         });
12261       }
12262     }
12263
12264     return left;
12265   },
12266
12267   logicalOR: function() {
12268     var left = this.logicalAND();
12269     var token;
12270     while ((token = this.expect('||'))) {
12271       left = this.binaryFn(left, token.text, this.logicalAND(), true);
12272     }
12273     return left;
12274   },
12275
12276   logicalAND: function() {
12277     var left = this.equality();
12278     var token;
12279     while ((token = this.expect('&&'))) {
12280       left = this.binaryFn(left, token.text, this.equality(), true);
12281     }
12282     return left;
12283   },
12284
12285   equality: function() {
12286     var left = this.relational();
12287     var token;
12288     while ((token = this.expect('==','!=','===','!=='))) {
12289       left = this.binaryFn(left, token.text, this.relational());
12290     }
12291     return left;
12292   },
12293
12294   relational: function() {
12295     var left = this.additive();
12296     var token;
12297     while ((token = this.expect('<', '>', '<=', '>='))) {
12298       left = this.binaryFn(left, token.text, this.additive());
12299     }
12300     return left;
12301   },
12302
12303   additive: function() {
12304     var left = this.multiplicative();
12305     var token;
12306     while ((token = this.expect('+','-'))) {
12307       left = this.binaryFn(left, token.text, this.multiplicative());
12308     }
12309     return left;
12310   },
12311
12312   multiplicative: function() {
12313     var left = this.unary();
12314     var token;
12315     while ((token = this.expect('*','/','%'))) {
12316       left = this.binaryFn(left, token.text, this.unary());
12317     }
12318     return left;
12319   },
12320
12321   unary: function() {
12322     var token;
12323     if (this.expect('+')) {
12324       return this.primary();
12325     } else if ((token = this.expect('-'))) {
12326       return this.binaryFn(Parser.ZERO, token.text, this.unary());
12327     } else if ((token = this.expect('!'))) {
12328       return this.unaryFn(token.text, this.unary());
12329     } else {
12330       return this.primary();
12331     }
12332   },
12333
12334   fieldAccess: function(object) {
12335     var getter = this.identifier();
12336
12337     return extend(function $parseFieldAccess(scope, locals, self) {
12338       var o = self || object(scope, locals);
12339       return (o == null) ? undefined : getter(o);
12340     }, {
12341       assign: function(scope, value, locals) {
12342         var o = object(scope, locals);
12343         if (!o) object.assign(scope, o = {}, locals);
12344         return getter.assign(o, value);
12345       }
12346     });
12347   },
12348
12349   objectIndex: function(obj) {
12350     var expression = this.text;
12351
12352     var indexFn = this.expression();
12353     this.consume(']');
12354
12355     return extend(function $parseObjectIndex(self, locals) {
12356       var o = obj(self, locals),
12357           i = indexFn(self, locals),
12358           v;
12359
12360       ensureSafeMemberName(i, expression);
12361       if (!o) return undefined;
12362       v = ensureSafeObject(o[i], expression);
12363       return v;
12364     }, {
12365       assign: function(self, value, locals) {
12366         var key = ensureSafeMemberName(indexFn(self, locals), expression);
12367         // prevent overwriting of Function.constructor which would break ensureSafeObject check
12368         var o = ensureSafeObject(obj(self, locals), expression);
12369         if (!o) obj.assign(self, o = {}, locals);
12370         return o[key] = value;
12371       }
12372     });
12373   },
12374
12375   functionCall: function(fnGetter, contextGetter) {
12376     var argsFn = [];
12377     if (this.peekToken().text !== ')') {
12378       do {
12379         argsFn.push(this.expression());
12380       } while (this.expect(','));
12381     }
12382     this.consume(')');
12383
12384     var expressionText = this.text;
12385     // we can safely reuse the array across invocations
12386     var args = argsFn.length ? [] : null;
12387
12388     return function $parseFunctionCall(scope, locals) {
12389       var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
12390       var fn = fnGetter(scope, locals, context) || noop;
12391
12392       if (args) {
12393         var i = argsFn.length;
12394         while (i--) {
12395           args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
12396         }
12397       }
12398
12399       ensureSafeObject(context, expressionText);
12400       ensureSafeFunction(fn, expressionText);
12401
12402       // IE doesn't have apply for some native functions
12403       var v = fn.apply
12404             ? fn.apply(context, args)
12405             : fn(args[0], args[1], args[2], args[3], args[4]);
12406
12407       if (args) {
12408         // Free-up the memory (arguments of the last function call).
12409         args.length = 0;
12410       }
12411
12412       return ensureSafeObject(v, expressionText);
12413       };
12414   },
12415
12416   // This is used with json array declaration
12417   arrayDeclaration: function() {
12418     var elementFns = [];
12419     if (this.peekToken().text !== ']') {
12420       do {
12421         if (this.peek(']')) {
12422           // Support trailing commas per ES5.1.
12423           break;
12424         }
12425         elementFns.push(this.expression());
12426       } while (this.expect(','));
12427     }
12428     this.consume(']');
12429
12430     return extend(function $parseArrayLiteral(self, locals) {
12431       var array = [];
12432       for (var i = 0, ii = elementFns.length; i < ii; i++) {
12433         array.push(elementFns[i](self, locals));
12434       }
12435       return array;
12436     }, {
12437       literal: true,
12438       constant: elementFns.every(isConstant),
12439       inputs: elementFns
12440     });
12441   },
12442
12443   object: function() {
12444     var keys = [], valueFns = [];
12445     if (this.peekToken().text !== '}') {
12446       do {
12447         if (this.peek('}')) {
12448           // Support trailing commas per ES5.1.
12449           break;
12450         }
12451         var token = this.consume();
12452         if (token.constant) {
12453           keys.push(token.value);
12454         } else if (token.identifier) {
12455           keys.push(token.text);
12456         } else {
12457           this.throwError("invalid key", token);
12458         }
12459         this.consume(':');
12460         valueFns.push(this.expression());
12461       } while (this.expect(','));
12462     }
12463     this.consume('}');
12464
12465     return extend(function $parseObjectLiteral(self, locals) {
12466       var object = {};
12467       for (var i = 0, ii = valueFns.length; i < ii; i++) {
12468         object[keys[i]] = valueFns[i](self, locals);
12469       }
12470       return object;
12471     }, {
12472       literal: true,
12473       constant: valueFns.every(isConstant),
12474       inputs: valueFns
12475     });
12476   }
12477 };
12478
12479
12480 //////////////////////////////////////////////////
12481 // Parser helper functions
12482 //////////////////////////////////////////////////
12483
12484 function setter(obj, locals, path, setValue, fullExp) {
12485   ensureSafeObject(obj, fullExp);
12486   ensureSafeObject(locals, fullExp);
12487
12488   var element = path.split('.'), key;
12489   for (var i = 0; element.length > 1; i++) {
12490     key = ensureSafeMemberName(element.shift(), fullExp);
12491     var propertyObj = (i === 0 && locals && locals[key]) || obj[key];
12492     if (!propertyObj) {
12493       propertyObj = {};
12494       obj[key] = propertyObj;
12495     }
12496     obj = ensureSafeObject(propertyObj, fullExp);
12497   }
12498   key = ensureSafeMemberName(element.shift(), fullExp);
12499   ensureSafeObject(obj[key], fullExp);
12500   obj[key] = setValue;
12501   return setValue;
12502 }
12503
12504 var getterFnCacheDefault = createMap();
12505 var getterFnCacheExpensive = createMap();
12506
12507 function isPossiblyDangerousMemberName(name) {
12508   return name == 'constructor';
12509 }
12510
12511 /**
12512  * Implementation of the "Black Hole" variant from:
12513  * - http://jsperf.com/angularjs-parse-getter/4
12514  * - http://jsperf.com/path-evaluation-simplified/7
12515  */
12516 function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) {
12517   ensureSafeMemberName(key0, fullExp);
12518   ensureSafeMemberName(key1, fullExp);
12519   ensureSafeMemberName(key2, fullExp);
12520   ensureSafeMemberName(key3, fullExp);
12521   ensureSafeMemberName(key4, fullExp);
12522   var eso = function(o) {
12523     return ensureSafeObject(o, fullExp);
12524   };
12525   var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
12526   var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
12527   var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
12528   var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
12529   var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
12530
12531   return function cspSafeGetter(scope, locals) {
12532     var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
12533
12534     if (pathVal == null) return pathVal;
12535     pathVal = eso0(pathVal[key0]);
12536
12537     if (!key1) return pathVal;
12538     if (pathVal == null) return undefined;
12539     pathVal = eso1(pathVal[key1]);
12540
12541     if (!key2) return pathVal;
12542     if (pathVal == null) return undefined;
12543     pathVal = eso2(pathVal[key2]);
12544
12545     if (!key3) return pathVal;
12546     if (pathVal == null) return undefined;
12547     pathVal = eso3(pathVal[key3]);
12548
12549     if (!key4) return pathVal;
12550     if (pathVal == null) return undefined;
12551     pathVal = eso4(pathVal[key4]);
12552
12553     return pathVal;
12554   };
12555 }
12556
12557 function getterFnWithEnsureSafeObject(fn, fullExpression) {
12558   return function(s, l) {
12559     return fn(s, l, ensureSafeObject, fullExpression);
12560   };
12561 }
12562
12563 function getterFn(path, options, fullExp) {
12564   var expensiveChecks = options.expensiveChecks;
12565   var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
12566   var fn = getterFnCache[path];
12567   if (fn) return fn;
12568
12569
12570   var pathKeys = path.split('.'),
12571       pathKeysLength = pathKeys.length;
12572
12573   // http://jsperf.com/angularjs-parse-getter/6
12574   if (options.csp) {
12575     if (pathKeysLength < 6) {
12576       fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks);
12577     } else {
12578       fn = function cspSafeGetter(scope, locals) {
12579         var i = 0, val;
12580         do {
12581           val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
12582                                 pathKeys[i++], fullExp, expensiveChecks)(scope, locals);
12583
12584           locals = undefined; // clear after first iteration
12585           scope = val;
12586         } while (i < pathKeysLength);
12587         return val;
12588       };
12589     }
12590   } else {
12591     var code = '';
12592     if (expensiveChecks) {
12593       code += 's = eso(s, fe);\nl = eso(l, fe);\n';
12594     }
12595     var needsEnsureSafeObject = expensiveChecks;
12596     forEach(pathKeys, function(key, index) {
12597       ensureSafeMemberName(key, fullExp);
12598       var lookupJs = (index
12599                       // we simply dereference 's' on any .dot notation
12600                       ? 's'
12601                       // but if we are first then we check locals first, and if so read it first
12602                       : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key;
12603       if (expensiveChecks || isPossiblyDangerousMemberName(key)) {
12604         lookupJs = 'eso(' + lookupJs + ', fe)';
12605         needsEnsureSafeObject = true;
12606       }
12607       code += 'if(s == null) return undefined;\n' +
12608               's=' + lookupJs + ';\n';
12609     });
12610     code += 'return s;';
12611
12612     /* jshint -W054 */
12613     var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject
12614     /* jshint +W054 */
12615     evaledFnGetter.toString = valueFn(code);
12616     if (needsEnsureSafeObject) {
12617       evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp);
12618     }
12619     fn = evaledFnGetter;
12620   }
12621
12622   fn.sharedGetter = true;
12623   fn.assign = function(self, value, locals) {
12624     return setter(self, locals, path, value, path);
12625   };
12626   getterFnCache[path] = fn;
12627   return fn;
12628 }
12629
12630 var objectValueOf = Object.prototype.valueOf;
12631
12632 function getValueOf(value) {
12633   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
12634 }
12635
12636 ///////////////////////////////////
12637
12638 /**
12639  * @ngdoc service
12640  * @name $parse
12641  * @kind function
12642  *
12643  * @description
12644  *
12645  * Converts Angular {@link guide/expression expression} into a function.
12646  *
12647  * ```js
12648  *   var getter = $parse('user.name');
12649  *   var setter = getter.assign;
12650  *   var context = {user:{name:'angular'}};
12651  *   var locals = {user:{name:'local'}};
12652  *
12653  *   expect(getter(context)).toEqual('angular');
12654  *   setter(context, 'newValue');
12655  *   expect(context.user.name).toEqual('newValue');
12656  *   expect(getter(context, locals)).toEqual('local');
12657  * ```
12658  *
12659  *
12660  * @param {string} expression String expression to compile.
12661  * @returns {function(context, locals)} a function which represents the compiled expression:
12662  *
12663  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
12664  *      are evaluated against (typically a scope object).
12665  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
12666  *      `context`.
12667  *
12668  *    The returned function also has the following properties:
12669  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
12670  *        literal.
12671  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
12672  *        constant literals.
12673  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
12674  *        set to a function to change its value on the given context.
12675  *
12676  */
12677
12678
12679 /**
12680  * @ngdoc provider
12681  * @name $parseProvider
12682  *
12683  * @description
12684  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
12685  *  service.
12686  */
12687 function $ParseProvider() {
12688   var cacheDefault = createMap();
12689   var cacheExpensive = createMap();
12690
12691
12692
12693   this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
12694     var $parseOptions = {
12695           csp: $sniffer.csp,
12696           expensiveChecks: false
12697         },
12698         $parseOptionsExpensive = {
12699           csp: $sniffer.csp,
12700           expensiveChecks: true
12701         };
12702
12703     function wrapSharedExpression(exp) {
12704       var wrapped = exp;
12705
12706       if (exp.sharedGetter) {
12707         wrapped = function $parseWrapper(self, locals) {
12708           return exp(self, locals);
12709         };
12710         wrapped.literal = exp.literal;
12711         wrapped.constant = exp.constant;
12712         wrapped.assign = exp.assign;
12713       }
12714
12715       return wrapped;
12716     }
12717
12718     return function $parse(exp, interceptorFn, expensiveChecks) {
12719       var parsedExpression, oneTime, cacheKey;
12720
12721       switch (typeof exp) {
12722         case 'string':
12723           cacheKey = exp = exp.trim();
12724
12725           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
12726           parsedExpression = cache[cacheKey];
12727
12728           if (!parsedExpression) {
12729             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
12730               oneTime = true;
12731               exp = exp.substring(2);
12732             }
12733
12734             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
12735             var lexer = new Lexer(parseOptions);
12736             var parser = new Parser(lexer, $filter, parseOptions);
12737             parsedExpression = parser.parse(exp);
12738
12739             if (parsedExpression.constant) {
12740               parsedExpression.$$watchDelegate = constantWatchDelegate;
12741             } else if (oneTime) {
12742               //oneTime is not part of the exp passed to the Parser so we may have to
12743               //wrap the parsedExpression before adding a $$watchDelegate
12744               parsedExpression = wrapSharedExpression(parsedExpression);
12745               parsedExpression.$$watchDelegate = parsedExpression.literal ?
12746                 oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
12747             } else if (parsedExpression.inputs) {
12748               parsedExpression.$$watchDelegate = inputsWatchDelegate;
12749             }
12750
12751             cache[cacheKey] = parsedExpression;
12752           }
12753           return addInterceptor(parsedExpression, interceptorFn);
12754
12755         case 'function':
12756           return addInterceptor(exp, interceptorFn);
12757
12758         default:
12759           return addInterceptor(noop, interceptorFn);
12760       }
12761     };
12762
12763     function collectExpressionInputs(inputs, list) {
12764       for (var i = 0, ii = inputs.length; i < ii; i++) {
12765         var input = inputs[i];
12766         if (!input.constant) {
12767           if (input.inputs) {
12768             collectExpressionInputs(input.inputs, list);
12769           } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better?
12770             list.push(input);
12771           }
12772         }
12773       }
12774
12775       return list;
12776     }
12777
12778     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
12779
12780       if (newValue == null || oldValueOfValue == null) { // null/undefined
12781         return newValue === oldValueOfValue;
12782       }
12783
12784       if (typeof newValue === 'object') {
12785
12786         // attempt to convert the value to a primitive type
12787         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
12788         //             be cheaply dirty-checked
12789         newValue = getValueOf(newValue);
12790
12791         if (typeof newValue === 'object') {
12792           // objects/arrays are not supported - deep-watching them would be too expensive
12793           return false;
12794         }
12795
12796         // fall-through to the primitive equality check
12797       }
12798
12799       //Primitive or NaN
12800       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
12801     }
12802
12803     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12804       var inputExpressions = parsedExpression.$$inputs ||
12805                     (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, []));
12806
12807       var lastResult;
12808
12809       if (inputExpressions.length === 1) {
12810         var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails
12811         inputExpressions = inputExpressions[0];
12812         return scope.$watch(function expressionInputWatch(scope) {
12813           var newInputValue = inputExpressions(scope);
12814           if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) {
12815             lastResult = parsedExpression(scope);
12816             oldInputValue = newInputValue && getValueOf(newInputValue);
12817           }
12818           return lastResult;
12819         }, listener, objectEquality);
12820       }
12821
12822       var oldInputValueOfValues = [];
12823       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12824         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
12825       }
12826
12827       return scope.$watch(function expressionInputsWatch(scope) {
12828         var changed = false;
12829
12830         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12831           var newInputValue = inputExpressions[i](scope);
12832           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
12833             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
12834           }
12835         }
12836
12837         if (changed) {
12838           lastResult = parsedExpression(scope);
12839         }
12840
12841         return lastResult;
12842       }, listener, objectEquality);
12843     }
12844
12845     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12846       var unwatch, lastValue;
12847       return unwatch = scope.$watch(function oneTimeWatch(scope) {
12848         return parsedExpression(scope);
12849       }, function oneTimeListener(value, old, scope) {
12850         lastValue = value;
12851         if (isFunction(listener)) {
12852           listener.apply(this, arguments);
12853         }
12854         if (isDefined(value)) {
12855           scope.$$postDigest(function() {
12856             if (isDefined(lastValue)) {
12857               unwatch();
12858             }
12859           });
12860         }
12861       }, objectEquality);
12862     }
12863
12864     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12865       var unwatch, lastValue;
12866       return unwatch = scope.$watch(function oneTimeWatch(scope) {
12867         return parsedExpression(scope);
12868       }, function oneTimeListener(value, old, scope) {
12869         lastValue = value;
12870         if (isFunction(listener)) {
12871           listener.call(this, value, old, scope);
12872         }
12873         if (isAllDefined(value)) {
12874           scope.$$postDigest(function() {
12875             if (isAllDefined(lastValue)) unwatch();
12876           });
12877         }
12878       }, objectEquality);
12879
12880       function isAllDefined(value) {
12881         var allDefined = true;
12882         forEach(value, function(val) {
12883           if (!isDefined(val)) allDefined = false;
12884         });
12885         return allDefined;
12886       }
12887     }
12888
12889     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12890       var unwatch;
12891       return unwatch = scope.$watch(function constantWatch(scope) {
12892         return parsedExpression(scope);
12893       }, function constantListener(value, old, scope) {
12894         if (isFunction(listener)) {
12895           listener.apply(this, arguments);
12896         }
12897         unwatch();
12898       }, objectEquality);
12899     }
12900
12901     function addInterceptor(parsedExpression, interceptorFn) {
12902       if (!interceptorFn) return parsedExpression;
12903       var watchDelegate = parsedExpression.$$watchDelegate;
12904
12905       var regularWatch =
12906           watchDelegate !== oneTimeLiteralWatchDelegate &&
12907           watchDelegate !== oneTimeWatchDelegate;
12908
12909       var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
12910         var value = parsedExpression(scope, locals);
12911         return interceptorFn(value, scope, locals);
12912       } : function oneTimeInterceptedExpression(scope, locals) {
12913         var value = parsedExpression(scope, locals);
12914         var result = interceptorFn(value, scope, locals);
12915         // we only return the interceptor's result if the
12916         // initial value is defined (for bind-once)
12917         return isDefined(value) ? result : value;
12918       };
12919
12920       // Propagate $$watchDelegates other then inputsWatchDelegate
12921       if (parsedExpression.$$watchDelegate &&
12922           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
12923         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
12924       } else if (!interceptorFn.$stateful) {
12925         // If there is an interceptor, but no watchDelegate then treat the interceptor like
12926         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
12927         fn.$$watchDelegate = inputsWatchDelegate;
12928         fn.inputs = [parsedExpression];
12929       }
12930
12931       return fn;
12932     }
12933   }];
12934 }
12935
12936 /**
12937  * @ngdoc service
12938  * @name $q
12939  * @requires $rootScope
12940  *
12941  * @description
12942  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
12943  * when they are done processing.
12944  *
12945  * This is an implementation of promises/deferred objects inspired by
12946  * [Kris Kowal's Q](https://github.com/kriskowal/q).
12947  *
12948  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
12949  * implementations, and the other which resembles ES6 promises to some degree.
12950  *
12951  * # $q constructor
12952  *
12953  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
12954  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
12955  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
12956  *
12957  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
12958  * available yet.
12959  *
12960  * It can be used like so:
12961  *
12962  * ```js
12963  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
12964  *   // are available in the current lexical scope (they could have been injected or passed in).
12965  *
12966  *   function asyncGreet(name) {
12967  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
12968  *     return $q(function(resolve, reject) {
12969  *       setTimeout(function() {
12970  *         if (okToGreet(name)) {
12971  *           resolve('Hello, ' + name + '!');
12972  *         } else {
12973  *           reject('Greeting ' + name + ' is not allowed.');
12974  *         }
12975  *       }, 1000);
12976  *     });
12977  *   }
12978  *
12979  *   var promise = asyncGreet('Robin Hood');
12980  *   promise.then(function(greeting) {
12981  *     alert('Success: ' + greeting);
12982  *   }, function(reason) {
12983  *     alert('Failed: ' + reason);
12984  *   });
12985  * ```
12986  *
12987  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
12988  *
12989  * However, the more traditional CommonJS-style usage is still available, and documented below.
12990  *
12991  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
12992  * interface for interacting with an object that represents the result of an action that is
12993  * performed asynchronously, and may or may not be finished at any given point in time.
12994  *
12995  * From the perspective of dealing with error handling, deferred and promise APIs are to
12996  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
12997  *
12998  * ```js
12999  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
13000  *   // are available in the current lexical scope (they could have been injected or passed in).
13001  *
13002  *   function asyncGreet(name) {
13003  *     var deferred = $q.defer();
13004  *
13005  *     setTimeout(function() {
13006  *       deferred.notify('About to greet ' + name + '.');
13007  *
13008  *       if (okToGreet(name)) {
13009  *         deferred.resolve('Hello, ' + name + '!');
13010  *       } else {
13011  *         deferred.reject('Greeting ' + name + ' is not allowed.');
13012  *       }
13013  *     }, 1000);
13014  *
13015  *     return deferred.promise;
13016  *   }
13017  *
13018  *   var promise = asyncGreet('Robin Hood');
13019  *   promise.then(function(greeting) {
13020  *     alert('Success: ' + greeting);
13021  *   }, function(reason) {
13022  *     alert('Failed: ' + reason);
13023  *   }, function(update) {
13024  *     alert('Got notification: ' + update);
13025  *   });
13026  * ```
13027  *
13028  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
13029  * comes in the way of guarantees that promise and deferred APIs make, see
13030  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
13031  *
13032  * Additionally the promise api allows for composition that is very hard to do with the
13033  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
13034  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
13035  * section on serial or parallel joining of promises.
13036  *
13037  * # The Deferred API
13038  *
13039  * A new instance of deferred is constructed by calling `$q.defer()`.
13040  *
13041  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
13042  * that can be used for signaling the successful or unsuccessful completion, as well as the status
13043  * of the task.
13044  *
13045  * **Methods**
13046  *
13047  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
13048  *   constructed via `$q.reject`, the promise will be rejected instead.
13049  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
13050  *   resolving it with a rejection constructed via `$q.reject`.
13051  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
13052  *   multiple times before the promise is either resolved or rejected.
13053  *
13054  * **Properties**
13055  *
13056  * - promise – `{Promise}` – promise object associated with this deferred.
13057  *
13058  *
13059  * # The Promise API
13060  *
13061  * A new promise instance is created when a deferred instance is created and can be retrieved by
13062  * calling `deferred.promise`.
13063  *
13064  * The purpose of the promise object is to allow for interested parties to get access to the result
13065  * of the deferred task when it completes.
13066  *
13067  * **Methods**
13068  *
13069  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
13070  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
13071  *   as soon as the result is available. The callbacks are called with a single argument: the result
13072  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
13073  *   provide a progress indication, before the promise is resolved or rejected.
13074  *
13075  *   This method *returns a new promise* which is resolved or rejected via the return value of the
13076  *   `successCallback`, `errorCallback`. It also notifies via the return value of the
13077  *   `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback
13078  *   method.
13079  *
13080  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
13081  *
13082  * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
13083  *   but to do so without modifying the final value. This is useful to release resources or do some
13084  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
13085  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
13086  *   more information.
13087  *
13088  * # Chaining promises
13089  *
13090  * Because calling the `then` method of a promise returns a new derived promise, it is easily
13091  * possible to create a chain of promises:
13092  *
13093  * ```js
13094  *   promiseB = promiseA.then(function(result) {
13095  *     return result + 1;
13096  *   });
13097  *
13098  *   // promiseB will be resolved immediately after promiseA is resolved and its value
13099  *   // will be the result of promiseA incremented by 1
13100  * ```
13101  *
13102  * It is possible to create chains of any length and since a promise can be resolved with another
13103  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
13104  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
13105  * $http's response interceptors.
13106  *
13107  *
13108  * # Differences between Kris Kowal's Q and $q
13109  *
13110  *  There are two main differences:
13111  *
13112  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
13113  *   mechanism in angular, which means faster propagation of resolution or rejection into your
13114  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
13115  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
13116  *   all the important functionality needed for common async tasks.
13117  *
13118  *  # Testing
13119  *
13120  *  ```js
13121  *    it('should simulate promise', inject(function($q, $rootScope) {
13122  *      var deferred = $q.defer();
13123  *      var promise = deferred.promise;
13124  *      var resolvedValue;
13125  *
13126  *      promise.then(function(value) { resolvedValue = value; });
13127  *      expect(resolvedValue).toBeUndefined();
13128  *
13129  *      // Simulate resolving of promise
13130  *      deferred.resolve(123);
13131  *      // Note that the 'then' function does not get called synchronously.
13132  *      // This is because we want the promise API to always be async, whether or not
13133  *      // it got called synchronously or asynchronously.
13134  *      expect(resolvedValue).toBeUndefined();
13135  *
13136  *      // Propagate promise resolution to 'then' functions using $apply().
13137  *      $rootScope.$apply();
13138  *      expect(resolvedValue).toEqual(123);
13139  *    }));
13140  *  ```
13141  *
13142  * @param {function(function, function)} resolver Function which is responsible for resolving or
13143  *   rejecting the newly created promise. The first parameter is a function which resolves the
13144  *   promise, the second parameter is a function which rejects the promise.
13145  *
13146  * @returns {Promise} The newly created promise.
13147  */
13148 function $QProvider() {
13149
13150   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
13151     return qFactory(function(callback) {
13152       $rootScope.$evalAsync(callback);
13153     }, $exceptionHandler);
13154   }];
13155 }
13156
13157 function $$QProvider() {
13158   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
13159     return qFactory(function(callback) {
13160       $browser.defer(callback);
13161     }, $exceptionHandler);
13162   }];
13163 }
13164
13165 /**
13166  * Constructs a promise manager.
13167  *
13168  * @param {function(function)} nextTick Function for executing functions in the next turn.
13169  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
13170  *     debugging purposes.
13171  * @returns {object} Promise manager.
13172  */
13173 function qFactory(nextTick, exceptionHandler) {
13174   var $qMinErr = minErr('$q', TypeError);
13175   function callOnce(self, resolveFn, rejectFn) {
13176     var called = false;
13177     function wrap(fn) {
13178       return function(value) {
13179         if (called) return;
13180         called = true;
13181         fn.call(self, value);
13182       };
13183     }
13184
13185     return [wrap(resolveFn), wrap(rejectFn)];
13186   }
13187
13188   /**
13189    * @ngdoc method
13190    * @name ng.$q#defer
13191    * @kind function
13192    *
13193    * @description
13194    * Creates a `Deferred` object which represents a task which will finish in the future.
13195    *
13196    * @returns {Deferred} Returns a new instance of deferred.
13197    */
13198   var defer = function() {
13199     return new Deferred();
13200   };
13201
13202   function Promise() {
13203     this.$$state = { status: 0 };
13204   }
13205
13206   Promise.prototype = {
13207     then: function(onFulfilled, onRejected, progressBack) {
13208       var result = new Deferred();
13209
13210       this.$$state.pending = this.$$state.pending || [];
13211       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
13212       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
13213
13214       return result.promise;
13215     },
13216
13217     "catch": function(callback) {
13218       return this.then(null, callback);
13219     },
13220
13221     "finally": function(callback, progressBack) {
13222       return this.then(function(value) {
13223         return handleCallback(value, true, callback);
13224       }, function(error) {
13225         return handleCallback(error, false, callback);
13226       }, progressBack);
13227     }
13228   };
13229
13230   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
13231   function simpleBind(context, fn) {
13232     return function(value) {
13233       fn.call(context, value);
13234     };
13235   }
13236
13237   function processQueue(state) {
13238     var fn, promise, pending;
13239
13240     pending = state.pending;
13241     state.processScheduled = false;
13242     state.pending = undefined;
13243     for (var i = 0, ii = pending.length; i < ii; ++i) {
13244       promise = pending[i][0];
13245       fn = pending[i][state.status];
13246       try {
13247         if (isFunction(fn)) {
13248           promise.resolve(fn(state.value));
13249         } else if (state.status === 1) {
13250           promise.resolve(state.value);
13251         } else {
13252           promise.reject(state.value);
13253         }
13254       } catch (e) {
13255         promise.reject(e);
13256         exceptionHandler(e);
13257       }
13258     }
13259   }
13260
13261   function scheduleProcessQueue(state) {
13262     if (state.processScheduled || !state.pending) return;
13263     state.processScheduled = true;
13264     nextTick(function() { processQueue(state); });
13265   }
13266
13267   function Deferred() {
13268     this.promise = new Promise();
13269     //Necessary to support unbound execution :/
13270     this.resolve = simpleBind(this, this.resolve);
13271     this.reject = simpleBind(this, this.reject);
13272     this.notify = simpleBind(this, this.notify);
13273   }
13274
13275   Deferred.prototype = {
13276     resolve: function(val) {
13277       if (this.promise.$$state.status) return;
13278       if (val === this.promise) {
13279         this.$$reject($qMinErr(
13280           'qcycle',
13281           "Expected promise to be resolved with value other than itself '{0}'",
13282           val));
13283       } else {
13284         this.$$resolve(val);
13285       }
13286
13287     },
13288
13289     $$resolve: function(val) {
13290       var then, fns;
13291
13292       fns = callOnce(this, this.$$resolve, this.$$reject);
13293       try {
13294         if ((isObject(val) || isFunction(val))) then = val && val.then;
13295         if (isFunction(then)) {
13296           this.promise.$$state.status = -1;
13297           then.call(val, fns[0], fns[1], this.notify);
13298         } else {
13299           this.promise.$$state.value = val;
13300           this.promise.$$state.status = 1;
13301           scheduleProcessQueue(this.promise.$$state);
13302         }
13303       } catch (e) {
13304         fns[1](e);
13305         exceptionHandler(e);
13306       }
13307     },
13308
13309     reject: function(reason) {
13310       if (this.promise.$$state.status) return;
13311       this.$$reject(reason);
13312     },
13313
13314     $$reject: function(reason) {
13315       this.promise.$$state.value = reason;
13316       this.promise.$$state.status = 2;
13317       scheduleProcessQueue(this.promise.$$state);
13318     },
13319
13320     notify: function(progress) {
13321       var callbacks = this.promise.$$state.pending;
13322
13323       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
13324         nextTick(function() {
13325           var callback, result;
13326           for (var i = 0, ii = callbacks.length; i < ii; i++) {
13327             result = callbacks[i][0];
13328             callback = callbacks[i][3];
13329             try {
13330               result.notify(isFunction(callback) ? callback(progress) : progress);
13331             } catch (e) {
13332               exceptionHandler(e);
13333             }
13334           }
13335         });
13336       }
13337     }
13338   };
13339
13340   /**
13341    * @ngdoc method
13342    * @name $q#reject
13343    * @kind function
13344    *
13345    * @description
13346    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
13347    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
13348    * a promise chain, you don't need to worry about it.
13349    *
13350    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
13351    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
13352    * a promise error callback and you want to forward the error to the promise derived from the
13353    * current promise, you have to "rethrow" the error by returning a rejection constructed via
13354    * `reject`.
13355    *
13356    * ```js
13357    *   promiseB = promiseA.then(function(result) {
13358    *     // success: do something and resolve promiseB
13359    *     //          with the old or a new result
13360    *     return result;
13361    *   }, function(reason) {
13362    *     // error: handle the error if possible and
13363    *     //        resolve promiseB with newPromiseOrValue,
13364    *     //        otherwise forward the rejection to promiseB
13365    *     if (canHandle(reason)) {
13366    *      // handle the error and recover
13367    *      return newPromiseOrValue;
13368    *     }
13369    *     return $q.reject(reason);
13370    *   });
13371    * ```
13372    *
13373    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
13374    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
13375    */
13376   var reject = function(reason) {
13377     var result = new Deferred();
13378     result.reject(reason);
13379     return result.promise;
13380   };
13381
13382   var makePromise = function makePromise(value, resolved) {
13383     var result = new Deferred();
13384     if (resolved) {
13385       result.resolve(value);
13386     } else {
13387       result.reject(value);
13388     }
13389     return result.promise;
13390   };
13391
13392   var handleCallback = function handleCallback(value, isResolved, callback) {
13393     var callbackOutput = null;
13394     try {
13395       if (isFunction(callback)) callbackOutput = callback();
13396     } catch (e) {
13397       return makePromise(e, false);
13398     }
13399     if (isPromiseLike(callbackOutput)) {
13400       return callbackOutput.then(function() {
13401         return makePromise(value, isResolved);
13402       }, function(error) {
13403         return makePromise(error, false);
13404       });
13405     } else {
13406       return makePromise(value, isResolved);
13407     }
13408   };
13409
13410   /**
13411    * @ngdoc method
13412    * @name $q#when
13413    * @kind function
13414    *
13415    * @description
13416    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
13417    * This is useful when you are dealing with an object that might or might not be a promise, or if
13418    * the promise comes from a source that can't be trusted.
13419    *
13420    * @param {*} value Value or a promise
13421    * @returns {Promise} Returns a promise of the passed value or promise
13422    */
13423
13424
13425   var when = function(value, callback, errback, progressBack) {
13426     var result = new Deferred();
13427     result.resolve(value);
13428     return result.promise.then(callback, errback, progressBack);
13429   };
13430
13431   /**
13432    * @ngdoc method
13433    * @name $q#all
13434    * @kind function
13435    *
13436    * @description
13437    * Combines multiple promises into a single promise that is resolved when all of the input
13438    * promises are resolved.
13439    *
13440    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
13441    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
13442    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
13443    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
13444    *   with the same rejection value.
13445    */
13446
13447   function all(promises) {
13448     var deferred = new Deferred(),
13449         counter = 0,
13450         results = isArray(promises) ? [] : {};
13451
13452     forEach(promises, function(promise, key) {
13453       counter++;
13454       when(promise).then(function(value) {
13455         if (results.hasOwnProperty(key)) return;
13456         results[key] = value;
13457         if (!(--counter)) deferred.resolve(results);
13458       }, function(reason) {
13459         if (results.hasOwnProperty(key)) return;
13460         deferred.reject(reason);
13461       });
13462     });
13463
13464     if (counter === 0) {
13465       deferred.resolve(results);
13466     }
13467
13468     return deferred.promise;
13469   }
13470
13471   var $Q = function Q(resolver) {
13472     if (!isFunction(resolver)) {
13473       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
13474     }
13475
13476     if (!(this instanceof Q)) {
13477       // More useful when $Q is the Promise itself.
13478       return new Q(resolver);
13479     }
13480
13481     var deferred = new Deferred();
13482
13483     function resolveFn(value) {
13484       deferred.resolve(value);
13485     }
13486
13487     function rejectFn(reason) {
13488       deferred.reject(reason);
13489     }
13490
13491     resolver(resolveFn, rejectFn);
13492
13493     return deferred.promise;
13494   };
13495
13496   $Q.defer = defer;
13497   $Q.reject = reject;
13498   $Q.when = when;
13499   $Q.all = all;
13500
13501   return $Q;
13502 }
13503
13504 function $$RAFProvider() { //rAF
13505   this.$get = ['$window', '$timeout', function($window, $timeout) {
13506     var requestAnimationFrame = $window.requestAnimationFrame ||
13507                                 $window.webkitRequestAnimationFrame;
13508
13509     var cancelAnimationFrame = $window.cancelAnimationFrame ||
13510                                $window.webkitCancelAnimationFrame ||
13511                                $window.webkitCancelRequestAnimationFrame;
13512
13513     var rafSupported = !!requestAnimationFrame;
13514     var raf = rafSupported
13515       ? function(fn) {
13516           var id = requestAnimationFrame(fn);
13517           return function() {
13518             cancelAnimationFrame(id);
13519           };
13520         }
13521       : function(fn) {
13522           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
13523           return function() {
13524             $timeout.cancel(timer);
13525           };
13526         };
13527
13528     raf.supported = rafSupported;
13529
13530     return raf;
13531   }];
13532 }
13533
13534 /**
13535  * DESIGN NOTES
13536  *
13537  * The design decisions behind the scope are heavily favored for speed and memory consumption.
13538  *
13539  * The typical use of scope is to watch the expressions, which most of the time return the same
13540  * value as last time so we optimize the operation.
13541  *
13542  * Closures construction is expensive in terms of speed as well as memory:
13543  *   - No closures, instead use prototypical inheritance for API
13544  *   - Internal state needs to be stored on scope directly, which means that private state is
13545  *     exposed as $$____ properties
13546  *
13547  * Loop operations are optimized by using while(count--) { ... }
13548  *   - this means that in order to keep the same order of execution as addition we have to add
13549  *     items to the array at the beginning (unshift) instead of at the end (push)
13550  *
13551  * Child scopes are created and removed often
13552  *   - Using an array would be slow since inserts in middle are expensive so we use linked list
13553  *
13554  * There are few watches then a lot of observers. This is why you don't want the observer to be
13555  * implemented in the same way as watch. Watch requires return of initialization function which
13556  * are expensive to construct.
13557  */
13558
13559
13560 /**
13561  * @ngdoc provider
13562  * @name $rootScopeProvider
13563  * @description
13564  *
13565  * Provider for the $rootScope service.
13566  */
13567
13568 /**
13569  * @ngdoc method
13570  * @name $rootScopeProvider#digestTtl
13571  * @description
13572  *
13573  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
13574  * assuming that the model is unstable.
13575  *
13576  * The current default is 10 iterations.
13577  *
13578  * In complex applications it's possible that the dependencies between `$watch`s will result in
13579  * several digest iterations. However if an application needs more than the default 10 digest
13580  * iterations for its model to stabilize then you should investigate what is causing the model to
13581  * continuously change during the digest.
13582  *
13583  * Increasing the TTL could have performance implications, so you should not change it without
13584  * proper justification.
13585  *
13586  * @param {number} limit The number of digest iterations.
13587  */
13588
13589
13590 /**
13591  * @ngdoc service
13592  * @name $rootScope
13593  * @description
13594  *
13595  * Every application has a single root {@link ng.$rootScope.Scope scope}.
13596  * All other scopes are descendant scopes of the root scope. Scopes provide separation
13597  * between the model and the view, via a mechanism for watching the model for changes.
13598  * They also provide an event emission/broadcast and subscription facility. See the
13599  * {@link guide/scope developer guide on scopes}.
13600  */
13601 function $RootScopeProvider() {
13602   var TTL = 10;
13603   var $rootScopeMinErr = minErr('$rootScope');
13604   var lastDirtyWatch = null;
13605   var applyAsyncId = null;
13606
13607   this.digestTtl = function(value) {
13608     if (arguments.length) {
13609       TTL = value;
13610     }
13611     return TTL;
13612   };
13613
13614   function createChildScopeClass(parent) {
13615     function ChildScope() {
13616       this.$$watchers = this.$$nextSibling =
13617           this.$$childHead = this.$$childTail = null;
13618       this.$$listeners = {};
13619       this.$$listenerCount = {};
13620       this.$$watchersCount = 0;
13621       this.$id = nextUid();
13622       this.$$ChildScope = null;
13623     }
13624     ChildScope.prototype = parent;
13625     return ChildScope;
13626   }
13627
13628   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
13629       function($injector, $exceptionHandler, $parse, $browser) {
13630
13631     function destroyChildScope($event) {
13632         $event.currentScope.$$destroyed = true;
13633     }
13634
13635     /**
13636      * @ngdoc type
13637      * @name $rootScope.Scope
13638      *
13639      * @description
13640      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
13641      * {@link auto.$injector $injector}. Child scopes are created using the
13642      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
13643      * compiled HTML template is executed.)
13644      *
13645      * Here is a simple scope snippet to show how you can interact with the scope.
13646      * ```html
13647      * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
13648      * ```
13649      *
13650      * # Inheritance
13651      * A scope can inherit from a parent scope, as in this example:
13652      * ```js
13653          var parent = $rootScope;
13654          var child = parent.$new();
13655
13656          parent.salutation = "Hello";
13657          expect(child.salutation).toEqual('Hello');
13658
13659          child.salutation = "Welcome";
13660          expect(child.salutation).toEqual('Welcome');
13661          expect(parent.salutation).toEqual('Hello');
13662      * ```
13663      *
13664      * When interacting with `Scope` in tests, additional helper methods are available on the
13665      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
13666      * details.
13667      *
13668      *
13669      * @param {Object.<string, function()>=} providers Map of service factory which need to be
13670      *                                       provided for the current scope. Defaults to {@link ng}.
13671      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
13672      *                              append/override services provided by `providers`. This is handy
13673      *                              when unit-testing and having the need to override a default
13674      *                              service.
13675      * @returns {Object} Newly created scope.
13676      *
13677      */
13678     function Scope() {
13679       this.$id = nextUid();
13680       this.$$phase = this.$parent = this.$$watchers =
13681                      this.$$nextSibling = this.$$prevSibling =
13682                      this.$$childHead = this.$$childTail = null;
13683       this.$root = this;
13684       this.$$destroyed = false;
13685       this.$$listeners = {};
13686       this.$$listenerCount = {};
13687       this.$$isolateBindings = null;
13688     }
13689
13690     /**
13691      * @ngdoc property
13692      * @name $rootScope.Scope#$id
13693      *
13694      * @description
13695      * Unique scope ID (monotonically increasing) useful for debugging.
13696      */
13697
13698      /**
13699       * @ngdoc property
13700       * @name $rootScope.Scope#$parent
13701       *
13702       * @description
13703       * Reference to the parent scope.
13704       */
13705
13706       /**
13707        * @ngdoc property
13708        * @name $rootScope.Scope#$root
13709        *
13710        * @description
13711        * Reference to the root scope.
13712        */
13713
13714     Scope.prototype = {
13715       constructor: Scope,
13716       /**
13717        * @ngdoc method
13718        * @name $rootScope.Scope#$new
13719        * @kind function
13720        *
13721        * @description
13722        * Creates a new child {@link ng.$rootScope.Scope scope}.
13723        *
13724        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
13725        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
13726        *
13727        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
13728        * desired for the scope and its child scopes to be permanently detached from the parent and
13729        * thus stop participating in model change detection and listener notification by invoking.
13730        *
13731        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
13732        *         parent scope. The scope is isolated, as it can not see parent scope properties.
13733        *         When creating widgets, it is useful for the widget to not accidentally read parent
13734        *         state.
13735        *
13736        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
13737        *                              of the newly created scope. Defaults to `this` scope if not provided.
13738        *                              This is used when creating a transclude scope to correctly place it
13739        *                              in the scope hierarchy while maintaining the correct prototypical
13740        *                              inheritance.
13741        *
13742        * @returns {Object} The newly created child scope.
13743        *
13744        */
13745       $new: function(isolate, parent) {
13746         var child;
13747
13748         parent = parent || this;
13749
13750         if (isolate) {
13751           child = new Scope();
13752           child.$root = this.$root;
13753         } else {
13754           // Only create a child scope class if somebody asks for one,
13755           // but cache it to allow the VM to optimize lookups.
13756           if (!this.$$ChildScope) {
13757             this.$$ChildScope = createChildScopeClass(this);
13758           }
13759           child = new this.$$ChildScope();
13760         }
13761         child.$parent = parent;
13762         child.$$prevSibling = parent.$$childTail;
13763         if (parent.$$childHead) {
13764           parent.$$childTail.$$nextSibling = child;
13765           parent.$$childTail = child;
13766         } else {
13767           parent.$$childHead = parent.$$childTail = child;
13768         }
13769
13770         // When the new scope is not isolated or we inherit from `this`, and
13771         // the parent scope is destroyed, the property `$$destroyed` is inherited
13772         // prototypically. In all other cases, this property needs to be set
13773         // when the parent scope is destroyed.
13774         // The listener needs to be added after the parent is set
13775         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
13776
13777         return child;
13778       },
13779
13780       /**
13781        * @ngdoc method
13782        * @name $rootScope.Scope#$watch
13783        * @kind function
13784        *
13785        * @description
13786        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
13787        *
13788        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
13789        *   $digest()} and should return the value that will be watched. (Since
13790        *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
13791        *   `watchExpression` can execute multiple times per
13792        *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
13793        * - The `listener` is called only when the value from the current `watchExpression` and the
13794        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
13795        *   see below). Inequality is determined according to reference inequality,
13796        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
13797        *    via the `!==` Javascript operator, unless `objectEquality == true`
13798        *   (see next point)
13799        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
13800        *   according to the {@link angular.equals} function. To save the value of the object for
13801        *   later comparison, the {@link angular.copy} function is used. This therefore means that
13802        *   watching complex objects will have adverse memory and performance implications.
13803        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
13804        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
13805        *   iteration limit is 10 to prevent an infinite loop deadlock.
13806        *
13807        *
13808        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
13809        * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
13810        * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
13811        * change is detected, be prepared for multiple calls to your listener.)
13812        *
13813        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
13814        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
13815        * watcher. In rare cases, this is undesirable because the listener is called when the result
13816        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
13817        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
13818        * listener was called due to initialization.
13819        *
13820        *
13821        *
13822        * # Example
13823        * ```js
13824            // let's assume that scope was dependency injected as the $rootScope
13825            var scope = $rootScope;
13826            scope.name = 'misko';
13827            scope.counter = 0;
13828
13829            expect(scope.counter).toEqual(0);
13830            scope.$watch('name', function(newValue, oldValue) {
13831              scope.counter = scope.counter + 1;
13832            });
13833            expect(scope.counter).toEqual(0);
13834
13835            scope.$digest();
13836            // the listener is always called during the first $digest loop after it was registered
13837            expect(scope.counter).toEqual(1);
13838
13839            scope.$digest();
13840            // but now it will not be called unless the value changes
13841            expect(scope.counter).toEqual(1);
13842
13843            scope.name = 'adam';
13844            scope.$digest();
13845            expect(scope.counter).toEqual(2);
13846
13847
13848
13849            // Using a function as a watchExpression
13850            var food;
13851            scope.foodCounter = 0;
13852            expect(scope.foodCounter).toEqual(0);
13853            scope.$watch(
13854              // This function returns the value being watched. It is called for each turn of the $digest loop
13855              function() { return food; },
13856              // This is the change listener, called when the value returned from the above function changes
13857              function(newValue, oldValue) {
13858                if ( newValue !== oldValue ) {
13859                  // Only increment the counter if the value changed
13860                  scope.foodCounter = scope.foodCounter + 1;
13861                }
13862              }
13863            );
13864            // No digest has been run so the counter will be zero
13865            expect(scope.foodCounter).toEqual(0);
13866
13867            // Run the digest but since food has not changed count will still be zero
13868            scope.$digest();
13869            expect(scope.foodCounter).toEqual(0);
13870
13871            // Update food and run digest.  Now the counter will increment
13872            food = 'cheeseburger';
13873            scope.$digest();
13874            expect(scope.foodCounter).toEqual(1);
13875
13876        * ```
13877        *
13878        *
13879        *
13880        * @param {(function()|string)} watchExpression Expression that is evaluated on each
13881        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
13882        *    a call to the `listener`.
13883        *
13884        *    - `string`: Evaluated as {@link guide/expression expression}
13885        *    - `function(scope)`: called with current `scope` as a parameter.
13886        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
13887        *    of `watchExpression` changes.
13888        *
13889        *    - `newVal` contains the current value of the `watchExpression`
13890        *    - `oldVal` contains the previous value of the `watchExpression`
13891        *    - `scope` refers to the current scope
13892        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
13893        *     comparing for reference equality.
13894        * @returns {function()} Returns a deregistration function for this listener.
13895        */
13896       $watch: function(watchExp, listener, objectEquality) {
13897         var get = $parse(watchExp);
13898
13899         if (get.$$watchDelegate) {
13900           return get.$$watchDelegate(this, listener, objectEquality, get);
13901         }
13902         var scope = this,
13903             array = scope.$$watchers,
13904             watcher = {
13905               fn: listener,
13906               last: initWatchVal,
13907               get: get,
13908               exp: watchExp,
13909               eq: !!objectEquality
13910             };
13911
13912         lastDirtyWatch = null;
13913
13914         if (!isFunction(listener)) {
13915           watcher.fn = noop;
13916         }
13917
13918         if (!array) {
13919           array = scope.$$watchers = [];
13920         }
13921         // we use unshift since we use a while loop in $digest for speed.
13922         // the while loop reads in reverse order.
13923         array.unshift(watcher);
13924
13925         return function deregisterWatch() {
13926           arrayRemove(array, watcher);
13927           lastDirtyWatch = null;
13928         };
13929       },
13930
13931       /**
13932        * @ngdoc method
13933        * @name $rootScope.Scope#$watchGroup
13934        * @kind function
13935        *
13936        * @description
13937        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
13938        * If any one expression in the collection changes the `listener` is executed.
13939        *
13940        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
13941        *   call to $digest() to see if any items changes.
13942        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
13943        *
13944        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
13945        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
13946        *
13947        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
13948        *    expression in `watchExpressions` changes
13949        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
13950        *    those of `watchExpression`
13951        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
13952        *    those of `watchExpression`
13953        *    The `scope` refers to the current scope.
13954        * @returns {function()} Returns a de-registration function for all listeners.
13955        */
13956       $watchGroup: function(watchExpressions, listener) {
13957         var oldValues = new Array(watchExpressions.length);
13958         var newValues = new Array(watchExpressions.length);
13959         var deregisterFns = [];
13960         var self = this;
13961         var changeReactionScheduled = false;
13962         var firstRun = true;
13963
13964         if (!watchExpressions.length) {
13965           // No expressions means we call the listener ASAP
13966           var shouldCall = true;
13967           self.$evalAsync(function() {
13968             if (shouldCall) listener(newValues, newValues, self);
13969           });
13970           return function deregisterWatchGroup() {
13971             shouldCall = false;
13972           };
13973         }
13974
13975         if (watchExpressions.length === 1) {
13976           // Special case size of one
13977           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
13978             newValues[0] = value;
13979             oldValues[0] = oldValue;
13980             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
13981           });
13982         }
13983
13984         forEach(watchExpressions, function(expr, i) {
13985           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
13986             newValues[i] = value;
13987             oldValues[i] = oldValue;
13988             if (!changeReactionScheduled) {
13989               changeReactionScheduled = true;
13990               self.$evalAsync(watchGroupAction);
13991             }
13992           });
13993           deregisterFns.push(unwatchFn);
13994         });
13995
13996         function watchGroupAction() {
13997           changeReactionScheduled = false;
13998
13999           if (firstRun) {
14000             firstRun = false;
14001             listener(newValues, newValues, self);
14002           } else {
14003             listener(newValues, oldValues, self);
14004           }
14005         }
14006
14007         return function deregisterWatchGroup() {
14008           while (deregisterFns.length) {
14009             deregisterFns.shift()();
14010           }
14011         };
14012       },
14013
14014
14015       /**
14016        * @ngdoc method
14017        * @name $rootScope.Scope#$watchCollection
14018        * @kind function
14019        *
14020        * @description
14021        * Shallow watches the properties of an object and fires whenever any of the properties change
14022        * (for arrays, this implies watching the array items; for object maps, this implies watching
14023        * the properties). If a change is detected, the `listener` callback is fired.
14024        *
14025        * - The `obj` collection is observed via standard $watch operation and is examined on every
14026        *   call to $digest() to see if any items have been added, removed, or moved.
14027        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
14028        *   adding, removing, and moving items belonging to an object or array.
14029        *
14030        *
14031        * # Example
14032        * ```js
14033           $scope.names = ['igor', 'matias', 'misko', 'james'];
14034           $scope.dataCount = 4;
14035
14036           $scope.$watchCollection('names', function(newNames, oldNames) {
14037             $scope.dataCount = newNames.length;
14038           });
14039
14040           expect($scope.dataCount).toEqual(4);
14041           $scope.$digest();
14042
14043           //still at 4 ... no changes
14044           expect($scope.dataCount).toEqual(4);
14045
14046           $scope.names.pop();
14047           $scope.$digest();
14048
14049           //now there's been a change
14050           expect($scope.dataCount).toEqual(3);
14051        * ```
14052        *
14053        *
14054        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
14055        *    expression value should evaluate to an object or an array which is observed on each
14056        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
14057        *    collection will trigger a call to the `listener`.
14058        *
14059        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
14060        *    when a change is detected.
14061        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
14062        *    - The `oldCollection` object is a copy of the former collection data.
14063        *      Due to performance considerations, the`oldCollection` value is computed only if the
14064        *      `listener` function declares two or more arguments.
14065        *    - The `scope` argument refers to the current scope.
14066        *
14067        * @returns {function()} Returns a de-registration function for this listener. When the
14068        *    de-registration function is executed, the internal watch operation is terminated.
14069        */
14070       $watchCollection: function(obj, listener) {
14071         $watchCollectionInterceptor.$stateful = true;
14072
14073         var self = this;
14074         // the current value, updated on each dirty-check run
14075         var newValue;
14076         // a shallow copy of the newValue from the last dirty-check run,
14077         // updated to match newValue during dirty-check run
14078         var oldValue;
14079         // a shallow copy of the newValue from when the last change happened
14080         var veryOldValue;
14081         // only track veryOldValue if the listener is asking for it
14082         var trackVeryOldValue = (listener.length > 1);
14083         var changeDetected = 0;
14084         var changeDetector = $parse(obj, $watchCollectionInterceptor);
14085         var internalArray = [];
14086         var internalObject = {};
14087         var initRun = true;
14088         var oldLength = 0;
14089
14090         function $watchCollectionInterceptor(_value) {
14091           newValue = _value;
14092           var newLength, key, bothNaN, newItem, oldItem;
14093
14094           // If the new value is undefined, then return undefined as the watch may be a one-time watch
14095           if (isUndefined(newValue)) return;
14096
14097           if (!isObject(newValue)) { // if primitive
14098             if (oldValue !== newValue) {
14099               oldValue = newValue;
14100               changeDetected++;
14101             }
14102           } else if (isArrayLike(newValue)) {
14103             if (oldValue !== internalArray) {
14104               // we are transitioning from something which was not an array into array.
14105               oldValue = internalArray;
14106               oldLength = oldValue.length = 0;
14107               changeDetected++;
14108             }
14109
14110             newLength = newValue.length;
14111
14112             if (oldLength !== newLength) {
14113               // if lengths do not match we need to trigger change notification
14114               changeDetected++;
14115               oldValue.length = oldLength = newLength;
14116             }
14117             // copy the items to oldValue and look for changes.
14118             for (var i = 0; i < newLength; i++) {
14119               oldItem = oldValue[i];
14120               newItem = newValue[i];
14121
14122               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14123               if (!bothNaN && (oldItem !== newItem)) {
14124                 changeDetected++;
14125                 oldValue[i] = newItem;
14126               }
14127             }
14128           } else {
14129             if (oldValue !== internalObject) {
14130               // we are transitioning from something which was not an object into object.
14131               oldValue = internalObject = {};
14132               oldLength = 0;
14133               changeDetected++;
14134             }
14135             // copy the items to oldValue and look for changes.
14136             newLength = 0;
14137             for (key in newValue) {
14138               if (newValue.hasOwnProperty(key)) {
14139                 newLength++;
14140                 newItem = newValue[key];
14141                 oldItem = oldValue[key];
14142
14143                 if (key in oldValue) {
14144                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14145                   if (!bothNaN && (oldItem !== newItem)) {
14146                     changeDetected++;
14147                     oldValue[key] = newItem;
14148                   }
14149                 } else {
14150                   oldLength++;
14151                   oldValue[key] = newItem;
14152                   changeDetected++;
14153                 }
14154               }
14155             }
14156             if (oldLength > newLength) {
14157               // we used to have more keys, need to find them and destroy them.
14158               changeDetected++;
14159               for (key in oldValue) {
14160                 if (!newValue.hasOwnProperty(key)) {
14161                   oldLength--;
14162                   delete oldValue[key];
14163                 }
14164               }
14165             }
14166           }
14167           return changeDetected;
14168         }
14169
14170         function $watchCollectionAction() {
14171           if (initRun) {
14172             initRun = false;
14173             listener(newValue, newValue, self);
14174           } else {
14175             listener(newValue, veryOldValue, self);
14176           }
14177
14178           // make a copy for the next time a collection is changed
14179           if (trackVeryOldValue) {
14180             if (!isObject(newValue)) {
14181               //primitive
14182               veryOldValue = newValue;
14183             } else if (isArrayLike(newValue)) {
14184               veryOldValue = new Array(newValue.length);
14185               for (var i = 0; i < newValue.length; i++) {
14186                 veryOldValue[i] = newValue[i];
14187               }
14188             } else { // if object
14189               veryOldValue = {};
14190               for (var key in newValue) {
14191                 if (hasOwnProperty.call(newValue, key)) {
14192                   veryOldValue[key] = newValue[key];
14193                 }
14194               }
14195             }
14196           }
14197         }
14198
14199         return this.$watch(changeDetector, $watchCollectionAction);
14200       },
14201
14202       /**
14203        * @ngdoc method
14204        * @name $rootScope.Scope#$digest
14205        * @kind function
14206        *
14207        * @description
14208        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
14209        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
14210        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
14211        * until no more listeners are firing. This means that it is possible to get into an infinite
14212        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
14213        * iterations exceeds 10.
14214        *
14215        * Usually, you don't call `$digest()` directly in
14216        * {@link ng.directive:ngController controllers} or in
14217        * {@link ng.$compileProvider#directive directives}.
14218        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
14219        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
14220        *
14221        * If you want to be notified whenever `$digest()` is called,
14222        * you can register a `watchExpression` function with
14223        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
14224        *
14225        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
14226        *
14227        * # Example
14228        * ```js
14229            var scope = ...;
14230            scope.name = 'misko';
14231            scope.counter = 0;
14232
14233            expect(scope.counter).toEqual(0);
14234            scope.$watch('name', function(newValue, oldValue) {
14235              scope.counter = scope.counter + 1;
14236            });
14237            expect(scope.counter).toEqual(0);
14238
14239            scope.$digest();
14240            // the listener is always called during the first $digest loop after it was registered
14241            expect(scope.counter).toEqual(1);
14242
14243            scope.$digest();
14244            // but now it will not be called unless the value changes
14245            expect(scope.counter).toEqual(1);
14246
14247            scope.name = 'adam';
14248            scope.$digest();
14249            expect(scope.counter).toEqual(2);
14250        * ```
14251        *
14252        */
14253       $digest: function() {
14254         var watch, value, last,
14255             watchers,
14256             length,
14257             dirty, ttl = TTL,
14258             next, current, target = this,
14259             watchLog = [],
14260             logIdx, logMsg, asyncTask;
14261
14262         beginPhase('$digest');
14263         // Check for changes to browser url that happened in sync before the call to $digest
14264         $browser.$$checkUrlChange();
14265
14266         if (this === $rootScope && applyAsyncId !== null) {
14267           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
14268           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
14269           $browser.defer.cancel(applyAsyncId);
14270           flushApplyAsync();
14271         }
14272
14273         lastDirtyWatch = null;
14274
14275         do { // "while dirty" loop
14276           dirty = false;
14277           current = target;
14278
14279           while (asyncQueue.length) {
14280             try {
14281               asyncTask = asyncQueue.shift();
14282               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
14283             } catch (e) {
14284               $exceptionHandler(e);
14285             }
14286             lastDirtyWatch = null;
14287           }
14288
14289           traverseScopesLoop:
14290           do { // "traverse the scopes" loop
14291             if ((watchers = current.$$watchers)) {
14292               // process our watches
14293               length = watchers.length;
14294               while (length--) {
14295                 try {
14296                   watch = watchers[length];
14297                   // Most common watches are on primitives, in which case we can short
14298                   // circuit it with === operator, only when === fails do we use .equals
14299                   if (watch) {
14300                     if ((value = watch.get(current)) !== (last = watch.last) &&
14301                         !(watch.eq
14302                             ? equals(value, last)
14303                             : (typeof value === 'number' && typeof last === 'number'
14304                                && isNaN(value) && isNaN(last)))) {
14305                       dirty = true;
14306                       lastDirtyWatch = watch;
14307                       watch.last = watch.eq ? copy(value, null) : value;
14308                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
14309                       if (ttl < 5) {
14310                         logIdx = 4 - ttl;
14311                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
14312                         watchLog[logIdx].push({
14313                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
14314                           newVal: value,
14315                           oldVal: last
14316                         });
14317                       }
14318                     } else if (watch === lastDirtyWatch) {
14319                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
14320                       // have already been tested.
14321                       dirty = false;
14322                       break traverseScopesLoop;
14323                     }
14324                   }
14325                 } catch (e) {
14326                   $exceptionHandler(e);
14327                 }
14328               }
14329             }
14330
14331             // Insanity Warning: scope depth-first traversal
14332             // yes, this code is a bit crazy, but it works and we have tests to prove it!
14333             // this piece should be kept in sync with the traversal in $broadcast
14334             if (!(next = (current.$$childHead ||
14335                 (current !== target && current.$$nextSibling)))) {
14336               while (current !== target && !(next = current.$$nextSibling)) {
14337                 current = current.$parent;
14338               }
14339             }
14340           } while ((current = next));
14341
14342           // `break traverseScopesLoop;` takes us to here
14343
14344           if ((dirty || asyncQueue.length) && !(ttl--)) {
14345             clearPhase();
14346             throw $rootScopeMinErr('infdig',
14347                 '{0} $digest() iterations reached. Aborting!\n' +
14348                 'Watchers fired in the last 5 iterations: {1}',
14349                 TTL, watchLog);
14350           }
14351
14352         } while (dirty || asyncQueue.length);
14353
14354         clearPhase();
14355
14356         while (postDigestQueue.length) {
14357           try {
14358             postDigestQueue.shift()();
14359           } catch (e) {
14360             $exceptionHandler(e);
14361           }
14362         }
14363       },
14364
14365
14366       /**
14367        * @ngdoc event
14368        * @name $rootScope.Scope#$destroy
14369        * @eventType broadcast on scope being destroyed
14370        *
14371        * @description
14372        * Broadcasted when a scope and its children are being destroyed.
14373        *
14374        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14375        * clean up DOM bindings before an element is removed from the DOM.
14376        */
14377
14378       /**
14379        * @ngdoc method
14380        * @name $rootScope.Scope#$destroy
14381        * @kind function
14382        *
14383        * @description
14384        * Removes the current scope (and all of its children) from the parent scope. Removal implies
14385        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
14386        * propagate to the current scope and its children. Removal also implies that the current
14387        * scope is eligible for garbage collection.
14388        *
14389        * The `$destroy()` is usually used by directives such as
14390        * {@link ng.directive:ngRepeat ngRepeat} for managing the
14391        * unrolling of the loop.
14392        *
14393        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
14394        * Application code can register a `$destroy` event handler that will give it a chance to
14395        * perform any necessary cleanup.
14396        *
14397        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14398        * clean up DOM bindings before an element is removed from the DOM.
14399        */
14400       $destroy: function() {
14401         // we can't destroy the root scope or a scope that has been already destroyed
14402         if (this.$$destroyed) return;
14403         var parent = this.$parent;
14404
14405         this.$broadcast('$destroy');
14406         this.$$destroyed = true;
14407         if (this === $rootScope) return;
14408
14409         for (var eventName in this.$$listenerCount) {
14410           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
14411         }
14412
14413         // sever all the references to parent scopes (after this cleanup, the current scope should
14414         // not be retained by any of our references and should be eligible for garbage collection)
14415         if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
14416         if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
14417         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
14418         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
14419
14420         // Disable listeners, watchers and apply/digest methods
14421         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
14422         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
14423         this.$$listeners = {};
14424
14425         // All of the code below is bogus code that works around V8's memory leak via optimized code
14426         // and inline caches.
14427         //
14428         // see:
14429         // - https://code.google.com/p/v8/issues/detail?id=2073#c26
14430         // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
14431         // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
14432
14433         this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
14434             this.$$childTail = this.$root = this.$$watchers = null;
14435       },
14436
14437       /**
14438        * @ngdoc method
14439        * @name $rootScope.Scope#$eval
14440        * @kind function
14441        *
14442        * @description
14443        * Executes the `expression` on the current scope and returns the result. Any exceptions in
14444        * the expression are propagated (uncaught). This is useful when evaluating Angular
14445        * expressions.
14446        *
14447        * # Example
14448        * ```js
14449            var scope = ng.$rootScope.Scope();
14450            scope.a = 1;
14451            scope.b = 2;
14452
14453            expect(scope.$eval('a+b')).toEqual(3);
14454            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
14455        * ```
14456        *
14457        * @param {(string|function())=} expression An angular expression to be executed.
14458        *
14459        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
14460        *    - `function(scope)`: execute the function with the current `scope` parameter.
14461        *
14462        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14463        * @returns {*} The result of evaluating the expression.
14464        */
14465       $eval: function(expr, locals) {
14466         return $parse(expr)(this, locals);
14467       },
14468
14469       /**
14470        * @ngdoc method
14471        * @name $rootScope.Scope#$evalAsync
14472        * @kind function
14473        *
14474        * @description
14475        * Executes the expression on the current scope at a later point in time.
14476        *
14477        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
14478        * that:
14479        *
14480        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
14481        *     rendering).
14482        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
14483        *     `expression` execution.
14484        *
14485        * Any exceptions from the execution of the expression are forwarded to the
14486        * {@link ng.$exceptionHandler $exceptionHandler} service.
14487        *
14488        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
14489        * will be scheduled. However, it is encouraged to always call code that changes the model
14490        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
14491        *
14492        * @param {(string|function())=} expression An angular expression to be executed.
14493        *
14494        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14495        *    - `function(scope)`: execute the function with the current `scope` parameter.
14496        *
14497        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14498        */
14499       $evalAsync: function(expr, locals) {
14500         // if we are outside of an $digest loop and this is the first time we are scheduling async
14501         // task also schedule async auto-flush
14502         if (!$rootScope.$$phase && !asyncQueue.length) {
14503           $browser.defer(function() {
14504             if (asyncQueue.length) {
14505               $rootScope.$digest();
14506             }
14507           });
14508         }
14509
14510         asyncQueue.push({scope: this, expression: expr, locals: locals});
14511       },
14512
14513       $$postDigest: function(fn) {
14514         postDigestQueue.push(fn);
14515       },
14516
14517       /**
14518        * @ngdoc method
14519        * @name $rootScope.Scope#$apply
14520        * @kind function
14521        *
14522        * @description
14523        * `$apply()` is used to execute an expression in angular from outside of the angular
14524        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
14525        * Because we are calling into the angular framework we need to perform proper scope life
14526        * cycle of {@link ng.$exceptionHandler exception handling},
14527        * {@link ng.$rootScope.Scope#$digest executing watches}.
14528        *
14529        * ## Life cycle
14530        *
14531        * # Pseudo-Code of `$apply()`
14532        * ```js
14533            function $apply(expr) {
14534              try {
14535                return $eval(expr);
14536              } catch (e) {
14537                $exceptionHandler(e);
14538              } finally {
14539                $root.$digest();
14540              }
14541            }
14542        * ```
14543        *
14544        *
14545        * Scope's `$apply()` method transitions through the following stages:
14546        *
14547        * 1. The {@link guide/expression expression} is executed using the
14548        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
14549        * 2. Any exceptions from the execution of the expression are forwarded to the
14550        *    {@link ng.$exceptionHandler $exceptionHandler} service.
14551        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
14552        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
14553        *
14554        *
14555        * @param {(string|function())=} exp An angular expression to be executed.
14556        *
14557        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14558        *    - `function(scope)`: execute the function with current `scope` parameter.
14559        *
14560        * @returns {*} The result of evaluating the expression.
14561        */
14562       $apply: function(expr) {
14563         try {
14564           beginPhase('$apply');
14565           return this.$eval(expr);
14566         } catch (e) {
14567           $exceptionHandler(e);
14568         } finally {
14569           clearPhase();
14570           try {
14571             $rootScope.$digest();
14572           } catch (e) {
14573             $exceptionHandler(e);
14574             throw e;
14575           }
14576         }
14577       },
14578
14579       /**
14580        * @ngdoc method
14581        * @name $rootScope.Scope#$applyAsync
14582        * @kind function
14583        *
14584        * @description
14585        * Schedule the invocation of $apply to occur at a later time. The actual time difference
14586        * varies across browsers, but is typically around ~10 milliseconds.
14587        *
14588        * This can be used to queue up multiple expressions which need to be evaluated in the same
14589        * digest.
14590        *
14591        * @param {(string|function())=} exp An angular expression to be executed.
14592        *
14593        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14594        *    - `function(scope)`: execute the function with current `scope` parameter.
14595        */
14596       $applyAsync: function(expr) {
14597         var scope = this;
14598         expr && applyAsyncQueue.push($applyAsyncExpression);
14599         scheduleApplyAsync();
14600
14601         function $applyAsyncExpression() {
14602           scope.$eval(expr);
14603         }
14604       },
14605
14606       /**
14607        * @ngdoc method
14608        * @name $rootScope.Scope#$on
14609        * @kind function
14610        *
14611        * @description
14612        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
14613        * discussion of event life cycle.
14614        *
14615        * The event listener function format is: `function(event, args...)`. The `event` object
14616        * passed into the listener has the following attributes:
14617        *
14618        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
14619        *     `$broadcast`-ed.
14620        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
14621        *     event propagates through the scope hierarchy, this property is set to null.
14622        *   - `name` - `{string}`: name of the event.
14623        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
14624        *     further event propagation (available only for events that were `$emit`-ed).
14625        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
14626        *     to true.
14627        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
14628        *
14629        * @param {string} name Event name to listen on.
14630        * @param {function(event, ...args)} listener Function to call when the event is emitted.
14631        * @returns {function()} Returns a deregistration function for this listener.
14632        */
14633       $on: function(name, listener) {
14634         var namedListeners = this.$$listeners[name];
14635         if (!namedListeners) {
14636           this.$$listeners[name] = namedListeners = [];
14637         }
14638         namedListeners.push(listener);
14639
14640         var current = this;
14641         do {
14642           if (!current.$$listenerCount[name]) {
14643             current.$$listenerCount[name] = 0;
14644           }
14645           current.$$listenerCount[name]++;
14646         } while ((current = current.$parent));
14647
14648         var self = this;
14649         return function() {
14650           var indexOfListener = namedListeners.indexOf(listener);
14651           if (indexOfListener !== -1) {
14652             namedListeners[indexOfListener] = null;
14653             decrementListenerCount(self, 1, name);
14654           }
14655         };
14656       },
14657
14658
14659       /**
14660        * @ngdoc method
14661        * @name $rootScope.Scope#$emit
14662        * @kind function
14663        *
14664        * @description
14665        * Dispatches an event `name` upwards through the scope hierarchy notifying the
14666        * registered {@link ng.$rootScope.Scope#$on} listeners.
14667        *
14668        * The event life cycle starts at the scope on which `$emit` was called. All
14669        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14670        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
14671        * registered listeners along the way. The event will stop propagating if one of the listeners
14672        * cancels it.
14673        *
14674        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14675        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14676        *
14677        * @param {string} name Event name to emit.
14678        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14679        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
14680        */
14681       $emit: function(name, args) {
14682         var empty = [],
14683             namedListeners,
14684             scope = this,
14685             stopPropagation = false,
14686             event = {
14687               name: name,
14688               targetScope: scope,
14689               stopPropagation: function() {stopPropagation = true;},
14690               preventDefault: function() {
14691                 event.defaultPrevented = true;
14692               },
14693               defaultPrevented: false
14694             },
14695             listenerArgs = concat([event], arguments, 1),
14696             i, length;
14697
14698         do {
14699           namedListeners = scope.$$listeners[name] || empty;
14700           event.currentScope = scope;
14701           for (i = 0, length = namedListeners.length; i < length; i++) {
14702
14703             // if listeners were deregistered, defragment the array
14704             if (!namedListeners[i]) {
14705               namedListeners.splice(i, 1);
14706               i--;
14707               length--;
14708               continue;
14709             }
14710             try {
14711               //allow all listeners attached to the current scope to run
14712               namedListeners[i].apply(null, listenerArgs);
14713             } catch (e) {
14714               $exceptionHandler(e);
14715             }
14716           }
14717           //if any listener on the current scope stops propagation, prevent bubbling
14718           if (stopPropagation) {
14719             event.currentScope = null;
14720             return event;
14721           }
14722           //traverse upwards
14723           scope = scope.$parent;
14724         } while (scope);
14725
14726         event.currentScope = null;
14727
14728         return event;
14729       },
14730
14731
14732       /**
14733        * @ngdoc method
14734        * @name $rootScope.Scope#$broadcast
14735        * @kind function
14736        *
14737        * @description
14738        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
14739        * registered {@link ng.$rootScope.Scope#$on} listeners.
14740        *
14741        * The event life cycle starts at the scope on which `$broadcast` was called. All
14742        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14743        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
14744        * scope and calls all registered listeners along the way. The event cannot be canceled.
14745        *
14746        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14747        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14748        *
14749        * @param {string} name Event name to broadcast.
14750        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14751        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
14752        */
14753       $broadcast: function(name, args) {
14754         var target = this,
14755             current = target,
14756             next = target,
14757             event = {
14758               name: name,
14759               targetScope: target,
14760               preventDefault: function() {
14761                 event.defaultPrevented = true;
14762               },
14763               defaultPrevented: false
14764             };
14765
14766         if (!target.$$listenerCount[name]) return event;
14767
14768         var listenerArgs = concat([event], arguments, 1),
14769             listeners, i, length;
14770
14771         //down while you can, then up and next sibling or up and next sibling until back at root
14772         while ((current = next)) {
14773           event.currentScope = current;
14774           listeners = current.$$listeners[name] || [];
14775           for (i = 0, length = listeners.length; i < length; i++) {
14776             // if listeners were deregistered, defragment the array
14777             if (!listeners[i]) {
14778               listeners.splice(i, 1);
14779               i--;
14780               length--;
14781               continue;
14782             }
14783
14784             try {
14785               listeners[i].apply(null, listenerArgs);
14786             } catch (e) {
14787               $exceptionHandler(e);
14788             }
14789           }
14790
14791           // Insanity Warning: scope depth-first traversal
14792           // yes, this code is a bit crazy, but it works and we have tests to prove it!
14793           // this piece should be kept in sync with the traversal in $digest
14794           // (though it differs due to having the extra check for $$listenerCount)
14795           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
14796               (current !== target && current.$$nextSibling)))) {
14797             while (current !== target && !(next = current.$$nextSibling)) {
14798               current = current.$parent;
14799             }
14800           }
14801         }
14802
14803         event.currentScope = null;
14804         return event;
14805       }
14806     };
14807
14808     var $rootScope = new Scope();
14809
14810     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
14811     var asyncQueue = $rootScope.$$asyncQueue = [];
14812     var postDigestQueue = $rootScope.$$postDigestQueue = [];
14813     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
14814
14815     return $rootScope;
14816
14817
14818     function beginPhase(phase) {
14819       if ($rootScope.$$phase) {
14820         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
14821       }
14822
14823       $rootScope.$$phase = phase;
14824     }
14825
14826     function clearPhase() {
14827       $rootScope.$$phase = null;
14828     }
14829
14830
14831     function decrementListenerCount(current, count, name) {
14832       do {
14833         current.$$listenerCount[name] -= count;
14834
14835         if (current.$$listenerCount[name] === 0) {
14836           delete current.$$listenerCount[name];
14837         }
14838       } while ((current = current.$parent));
14839     }
14840
14841     /**
14842      * function used as an initial value for watchers.
14843      * because it's unique we can easily tell it apart from other values
14844      */
14845     function initWatchVal() {}
14846
14847     function flushApplyAsync() {
14848       while (applyAsyncQueue.length) {
14849         try {
14850           applyAsyncQueue.shift()();
14851         } catch (e) {
14852           $exceptionHandler(e);
14853         }
14854       }
14855       applyAsyncId = null;
14856     }
14857
14858     function scheduleApplyAsync() {
14859       if (applyAsyncId === null) {
14860         applyAsyncId = $browser.defer(function() {
14861           $rootScope.$apply(flushApplyAsync);
14862         });
14863       }
14864     }
14865   }];
14866 }
14867
14868 /**
14869  * @description
14870  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
14871  */
14872 function $$SanitizeUriProvider() {
14873   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
14874     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
14875
14876   /**
14877    * @description
14878    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
14879    * urls during a[href] sanitization.
14880    *
14881    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
14882    *
14883    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
14884    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
14885    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
14886    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
14887    *
14888    * @param {RegExp=} regexp New regexp to whitelist urls with.
14889    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
14890    *    chaining otherwise.
14891    */
14892   this.aHrefSanitizationWhitelist = function(regexp) {
14893     if (isDefined(regexp)) {
14894       aHrefSanitizationWhitelist = regexp;
14895       return this;
14896     }
14897     return aHrefSanitizationWhitelist;
14898   };
14899
14900
14901   /**
14902    * @description
14903    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
14904    * urls during img[src] sanitization.
14905    *
14906    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
14907    *
14908    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
14909    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
14910    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
14911    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
14912    *
14913    * @param {RegExp=} regexp New regexp to whitelist urls with.
14914    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
14915    *    chaining otherwise.
14916    */
14917   this.imgSrcSanitizationWhitelist = function(regexp) {
14918     if (isDefined(regexp)) {
14919       imgSrcSanitizationWhitelist = regexp;
14920       return this;
14921     }
14922     return imgSrcSanitizationWhitelist;
14923   };
14924
14925   this.$get = function() {
14926     return function sanitizeUri(uri, isImage) {
14927       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
14928       var normalizedVal;
14929       normalizedVal = urlResolve(uri).href;
14930       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
14931         return 'unsafe:' + normalizedVal;
14932       }
14933       return uri;
14934     };
14935   };
14936 }
14937
14938 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
14939  *     Any commits to this file should be reviewed with security in mind.  *
14940  *   Changes to this file can potentially create security vulnerabilities. *
14941  *          An approval from 2 Core members with history of modifying      *
14942  *                         this file is required.                          *
14943  *                                                                         *
14944  *  Does the change somehow allow for arbitrary javascript to be executed? *
14945  *    Or allows for someone to change the prototype of built-in objects?   *
14946  *     Or gives undesired access to variables likes document or window?    *
14947  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14948
14949 var $sceMinErr = minErr('$sce');
14950
14951 var SCE_CONTEXTS = {
14952   HTML: 'html',
14953   CSS: 'css',
14954   URL: 'url',
14955   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
14956   // url.  (e.g. ng-include, script src, templateUrl)
14957   RESOURCE_URL: 'resourceUrl',
14958   JS: 'js'
14959 };
14960
14961 // Helper functions follow.
14962
14963 function adjustMatcher(matcher) {
14964   if (matcher === 'self') {
14965     return matcher;
14966   } else if (isString(matcher)) {
14967     // Strings match exactly except for 2 wildcards - '*' and '**'.
14968     // '*' matches any character except those from the set ':/.?&'.
14969     // '**' matches any character (like .* in a RegExp).
14970     // More than 2 *'s raises an error as it's ill defined.
14971     if (matcher.indexOf('***') > -1) {
14972       throw $sceMinErr('iwcard',
14973           'Illegal sequence *** in string matcher.  String: {0}', matcher);
14974     }
14975     matcher = escapeForRegexp(matcher).
14976                   replace('\\*\\*', '.*').
14977                   replace('\\*', '[^:/.?&;]*');
14978     return new RegExp('^' + matcher + '$');
14979   } else if (isRegExp(matcher)) {
14980     // The only other type of matcher allowed is a Regexp.
14981     // Match entire URL / disallow partial matches.
14982     // Flags are reset (i.e. no global, ignoreCase or multiline)
14983     return new RegExp('^' + matcher.source + '$');
14984   } else {
14985     throw $sceMinErr('imatcher',
14986         'Matchers may only be "self", string patterns or RegExp objects');
14987   }
14988 }
14989
14990
14991 function adjustMatchers(matchers) {
14992   var adjustedMatchers = [];
14993   if (isDefined(matchers)) {
14994     forEach(matchers, function(matcher) {
14995       adjustedMatchers.push(adjustMatcher(matcher));
14996     });
14997   }
14998   return adjustedMatchers;
14999 }
15000
15001
15002 /**
15003  * @ngdoc service
15004  * @name $sceDelegate
15005  * @kind function
15006  *
15007  * @description
15008  *
15009  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
15010  * Contextual Escaping (SCE)} services to AngularJS.
15011  *
15012  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
15013  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
15014  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
15015  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
15016  * work because `$sce` delegates to `$sceDelegate` for these operations.
15017  *
15018  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
15019  *
15020  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
15021  * can override it completely to change the behavior of `$sce`, the common case would
15022  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
15023  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
15024  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
15025  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
15026  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
15027  */
15028
15029 /**
15030  * @ngdoc provider
15031  * @name $sceDelegateProvider
15032  * @description
15033  *
15034  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
15035  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
15036  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
15037  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
15038  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
15039  *
15040  * For the general details about this service in Angular, read the main page for {@link ng.$sce
15041  * Strict Contextual Escaping (SCE)}.
15042  *
15043  * **Example**:  Consider the following case. <a name="example"></a>
15044  *
15045  * - your app is hosted at url `http://myapp.example.com/`
15046  * - but some of your templates are hosted on other domains you control such as
15047  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
15048  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
15049  *
15050  * Here is what a secure configuration for this scenario might look like:
15051  *
15052  * ```
15053  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
15054  *    $sceDelegateProvider.resourceUrlWhitelist([
15055  *      // Allow same origin resource loads.
15056  *      'self',
15057  *      // Allow loading from our assets domain.  Notice the difference between * and **.
15058  *      'http://srv*.assets.example.com/**'
15059  *    ]);
15060  *
15061  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
15062  *    $sceDelegateProvider.resourceUrlBlacklist([
15063  *      'http://myapp.example.com/clickThru**'
15064  *    ]);
15065  *  });
15066  * ```
15067  */
15068
15069 function $SceDelegateProvider() {
15070   this.SCE_CONTEXTS = SCE_CONTEXTS;
15071
15072   // Resource URLs can also be trusted by policy.
15073   var resourceUrlWhitelist = ['self'],
15074       resourceUrlBlacklist = [];
15075
15076   /**
15077    * @ngdoc method
15078    * @name $sceDelegateProvider#resourceUrlWhitelist
15079    * @kind function
15080    *
15081    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
15082    *     provided.  This must be an array or null.  A snapshot of this array is used so further
15083    *     changes to the array are ignored.
15084    *
15085    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15086    *     allowed in this array.
15087    *
15088    *     Note: **an empty whitelist array will block all URLs**!
15089    *
15090    * @return {Array} the currently set whitelist array.
15091    *
15092    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
15093    * same origin resource requests.
15094    *
15095    * @description
15096    * Sets/Gets the whitelist of trusted resource URLs.
15097    */
15098   this.resourceUrlWhitelist = function(value) {
15099     if (arguments.length) {
15100       resourceUrlWhitelist = adjustMatchers(value);
15101     }
15102     return resourceUrlWhitelist;
15103   };
15104
15105   /**
15106    * @ngdoc method
15107    * @name $sceDelegateProvider#resourceUrlBlacklist
15108    * @kind function
15109    *
15110    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
15111    *     provided.  This must be an array or null.  A snapshot of this array is used so further
15112    *     changes to the array are ignored.
15113    *
15114    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15115    *     allowed in this array.
15116    *
15117    *     The typical usage for the blacklist is to **block
15118    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
15119    *     these would otherwise be trusted but actually return content from the redirected domain.
15120    *
15121    *     Finally, **the blacklist overrides the whitelist** and has the final say.
15122    *
15123    * @return {Array} the currently set blacklist array.
15124    *
15125    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
15126    * is no blacklist.)
15127    *
15128    * @description
15129    * Sets/Gets the blacklist of trusted resource URLs.
15130    */
15131
15132   this.resourceUrlBlacklist = function(value) {
15133     if (arguments.length) {
15134       resourceUrlBlacklist = adjustMatchers(value);
15135     }
15136     return resourceUrlBlacklist;
15137   };
15138
15139   this.$get = ['$injector', function($injector) {
15140
15141     var htmlSanitizer = function htmlSanitizer(html) {
15142       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15143     };
15144
15145     if ($injector.has('$sanitize')) {
15146       htmlSanitizer = $injector.get('$sanitize');
15147     }
15148
15149
15150     function matchUrl(matcher, parsedUrl) {
15151       if (matcher === 'self') {
15152         return urlIsSameOrigin(parsedUrl);
15153       } else {
15154         // definitely a regex.  See adjustMatchers()
15155         return !!matcher.exec(parsedUrl.href);
15156       }
15157     }
15158
15159     function isResourceUrlAllowedByPolicy(url) {
15160       var parsedUrl = urlResolve(url.toString());
15161       var i, n, allowed = false;
15162       // Ensure that at least one item from the whitelist allows this url.
15163       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
15164         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
15165           allowed = true;
15166           break;
15167         }
15168       }
15169       if (allowed) {
15170         // Ensure that no item from the blacklist blocked this url.
15171         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
15172           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
15173             allowed = false;
15174             break;
15175           }
15176         }
15177       }
15178       return allowed;
15179     }
15180
15181     function generateHolderType(Base) {
15182       var holderType = function TrustedValueHolderType(trustedValue) {
15183         this.$$unwrapTrustedValue = function() {
15184           return trustedValue;
15185         };
15186       };
15187       if (Base) {
15188         holderType.prototype = new Base();
15189       }
15190       holderType.prototype.valueOf = function sceValueOf() {
15191         return this.$$unwrapTrustedValue();
15192       };
15193       holderType.prototype.toString = function sceToString() {
15194         return this.$$unwrapTrustedValue().toString();
15195       };
15196       return holderType;
15197     }
15198
15199     var trustedValueHolderBase = generateHolderType(),
15200         byType = {};
15201
15202     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
15203     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
15204     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
15205     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
15206     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
15207
15208     /**
15209      * @ngdoc method
15210      * @name $sceDelegate#trustAs
15211      *
15212      * @description
15213      * Returns an object that is trusted by angular for use in specified strict
15214      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
15215      * attribute interpolation, any dom event binding attribute interpolation
15216      * such as for onclick,  etc.) that uses the provided value.
15217      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
15218      *
15219      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15220      *   resourceUrl, html, js and css.
15221      * @param {*} value The value that that should be considered trusted/safe.
15222      * @returns {*} A value that can be used to stand in for the provided `value` in places
15223      * where Angular expects a $sce.trustAs() return value.
15224      */
15225     function trustAs(type, trustedValue) {
15226       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15227       if (!Constructor) {
15228         throw $sceMinErr('icontext',
15229             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
15230             type, trustedValue);
15231       }
15232       if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
15233         return trustedValue;
15234       }
15235       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
15236       // mutable objects, we ensure here that the value passed in is actually a string.
15237       if (typeof trustedValue !== 'string') {
15238         throw $sceMinErr('itype',
15239             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
15240             type);
15241       }
15242       return new Constructor(trustedValue);
15243     }
15244
15245     /**
15246      * @ngdoc method
15247      * @name $sceDelegate#valueOf
15248      *
15249      * @description
15250      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
15251      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
15252      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
15253      *
15254      * If the passed parameter is not a value that had been returned by {@link
15255      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
15256      *
15257      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
15258      *      call or anything else.
15259      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
15260      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
15261      *     `value` unchanged.
15262      */
15263     function valueOf(maybeTrusted) {
15264       if (maybeTrusted instanceof trustedValueHolderBase) {
15265         return maybeTrusted.$$unwrapTrustedValue();
15266       } else {
15267         return maybeTrusted;
15268       }
15269     }
15270
15271     /**
15272      * @ngdoc method
15273      * @name $sceDelegate#getTrusted
15274      *
15275      * @description
15276      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
15277      * returns the originally supplied value if the queried context type is a supertype of the
15278      * created type.  If this condition isn't satisfied, throws an exception.
15279      *
15280      * @param {string} type The kind of context in which this value is to be used.
15281      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
15282      *     `$sceDelegate.trustAs`} call.
15283      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
15284      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
15285      */
15286     function getTrusted(type, maybeTrusted) {
15287       if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
15288         return maybeTrusted;
15289       }
15290       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15291       if (constructor && maybeTrusted instanceof constructor) {
15292         return maybeTrusted.$$unwrapTrustedValue();
15293       }
15294       // If we get here, then we may only take one of two actions.
15295       // 1. sanitize the value for the requested type, or
15296       // 2. throw an exception.
15297       if (type === SCE_CONTEXTS.RESOURCE_URL) {
15298         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
15299           return maybeTrusted;
15300         } else {
15301           throw $sceMinErr('insecurl',
15302               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
15303               maybeTrusted.toString());
15304         }
15305       } else if (type === SCE_CONTEXTS.HTML) {
15306         return htmlSanitizer(maybeTrusted);
15307       }
15308       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15309     }
15310
15311     return { trustAs: trustAs,
15312              getTrusted: getTrusted,
15313              valueOf: valueOf };
15314   }];
15315 }
15316
15317
15318 /**
15319  * @ngdoc provider
15320  * @name $sceProvider
15321  * @description
15322  *
15323  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
15324  * -   enable/disable Strict Contextual Escaping (SCE) in a module
15325  * -   override the default implementation with a custom delegate
15326  *
15327  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
15328  */
15329
15330 /* jshint maxlen: false*/
15331
15332 /**
15333  * @ngdoc service
15334  * @name $sce
15335  * @kind function
15336  *
15337  * @description
15338  *
15339  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
15340  *
15341  * # Strict Contextual Escaping
15342  *
15343  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
15344  * contexts to result in a value that is marked as safe to use for that context.  One example of
15345  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
15346  * to these contexts as privileged or SCE contexts.
15347  *
15348  * As of version 1.2, Angular ships with SCE enabled by default.
15349  *
15350  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
15351  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
15352  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
15353  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
15354  * to the top of your HTML document.
15355  *
15356  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
15357  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
15358  *
15359  * Here's an example of a binding in a privileged context:
15360  *
15361  * ```
15362  * <input ng-model="userHtml">
15363  * <div ng-bind-html="userHtml"></div>
15364  * ```
15365  *
15366  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
15367  * disabled, this application allows the user to render arbitrary HTML into the DIV.
15368  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
15369  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
15370  * security vulnerabilities.)
15371  *
15372  * For the case of HTML, you might use a library, either on the client side, or on the server side,
15373  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
15374  *
15375  * How would you ensure that every place that used these types of bindings was bound to a value that
15376  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
15377  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
15378  * properties/fields and forgot to update the binding to the sanitized value?
15379  *
15380  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
15381  * determine that something explicitly says it's safe to use a value for binding in that
15382  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
15383  * for those values that you can easily tell are safe - because they were received from your server,
15384  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
15385  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
15386  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
15387  *
15388  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
15389  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
15390  * obtain values that will be accepted by SCE / privileged contexts.
15391  *
15392  *
15393  * ## How does it work?
15394  *
15395  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
15396  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
15397  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
15398  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
15399  *
15400  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
15401  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
15402  * simplified):
15403  *
15404  * ```
15405  * var ngBindHtmlDirective = ['$sce', function($sce) {
15406  *   return function(scope, element, attr) {
15407  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
15408  *       element.html(value || '');
15409  *     });
15410  *   };
15411  * }];
15412  * ```
15413  *
15414  * ## Impact on loading templates
15415  *
15416  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
15417  * `templateUrl`'s specified by {@link guide/directive directives}.
15418  *
15419  * By default, Angular only loads templates from the same domain and protocol as the application
15420  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
15421  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
15422  * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
15423  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
15424  *
15425  * *Please note*:
15426  * The browser's
15427  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
15428  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
15429  * policy apply in addition to this and may further restrict whether the template is successfully
15430  * loaded.  This means that without the right CORS policy, loading templates from a different domain
15431  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
15432  * browsers.
15433  *
15434  * ## This feels like too much overhead
15435  *
15436  * It's important to remember that SCE only applies to interpolation expressions.
15437  *
15438  * If your expressions are constant literals, they're automatically trusted and you don't need to
15439  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
15440  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
15441  *
15442  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
15443  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
15444  *
15445  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
15446  * templates in `ng-include` from your application's domain without having to even know about SCE.
15447  * It blocks loading templates from other domains or loading templates over http from an https
15448  * served document.  You can change these by setting your own custom {@link
15449  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
15450  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
15451  *
15452  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
15453  * application that's secure and can be audited to verify that with much more ease than bolting
15454  * security onto an application later.
15455  *
15456  * <a name="contexts"></a>
15457  * ## What trusted context types are supported?
15458  *
15459  * | Context             | Notes          |
15460  * |---------------------|----------------|
15461  * | `$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. |
15462  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
15463  * | `$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. |
15464  * | `$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. |
15465  * | `$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. |
15466  *
15467  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
15468  *
15469  *  Each element in these arrays must be one of the following:
15470  *
15471  *  - **'self'**
15472  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
15473  *      domain** as the application document using the **same protocol**.
15474  *  - **String** (except the special value `'self'`)
15475  *    - The string is matched against the full *normalized / absolute URL* of the resource
15476  *      being tested (substring matches are not good enough.)
15477  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
15478  *      match themselves.
15479  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
15480  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
15481  *      in a whitelist.
15482  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
15483  *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
15484  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
15485  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
15486  *      http://foo.example.com/templates/**).
15487  *  - **RegExp** (*see caveat below*)
15488  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
15489  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
15490  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
15491  *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
15492  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
15493  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
15494  *      is highly recommended to use the string patterns and only fall back to regular expressions
15495  *      if they as a last resort.
15496  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
15497  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
15498  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
15499  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
15500  *    - If you are generating your JavaScript from some other templating engine (not
15501  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
15502  *      remember to escape your regular expression (and be aware that you might need more than
15503  *      one level of escaping depending on your templating engine and the way you interpolated
15504  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
15505  *      enough before coding your own.  e.g. Ruby has
15506  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
15507  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
15508  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
15509  *      Closure library's [goog.string.regExpEscape(s)](
15510  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
15511  *
15512  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
15513  *
15514  * ## Show me an example using SCE.
15515  *
15516  * <example module="mySceApp" deps="angular-sanitize.js">
15517  * <file name="index.html">
15518  *   <div ng-controller="AppController as myCtrl">
15519  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
15520  *     <b>User comments</b><br>
15521  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
15522  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
15523  *     exploit.
15524  *     <div class="well">
15525  *       <div ng-repeat="userComment in myCtrl.userComments">
15526  *         <b>{{userComment.name}}</b>:
15527  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
15528  *         <br>
15529  *       </div>
15530  *     </div>
15531  *   </div>
15532  * </file>
15533  *
15534  * <file name="script.js">
15535  *   angular.module('mySceApp', ['ngSanitize'])
15536  *     .controller('AppController', ['$http', '$templateCache', '$sce',
15537  *       function($http, $templateCache, $sce) {
15538  *         var self = this;
15539  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
15540  *           self.userComments = userComments;
15541  *         });
15542  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
15543  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15544  *             'sanitization.&quot;">Hover over this text.</span>');
15545  *       }]);
15546  * </file>
15547  *
15548  * <file name="test_data.json">
15549  * [
15550  *   { "name": "Alice",
15551  *     "htmlComment":
15552  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
15553  *   },
15554  *   { "name": "Bob",
15555  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
15556  *   }
15557  * ]
15558  * </file>
15559  *
15560  * <file name="protractor.js" type="protractor">
15561  *   describe('SCE doc demo', function() {
15562  *     it('should sanitize untrusted values', function() {
15563  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
15564  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
15565  *     });
15566  *
15567  *     it('should NOT sanitize explicitly trusted values', function() {
15568  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
15569  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15570  *           'sanitization.&quot;">Hover over this text.</span>');
15571  *     });
15572  *   });
15573  * </file>
15574  * </example>
15575  *
15576  *
15577  *
15578  * ## Can I disable SCE completely?
15579  *
15580  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
15581  * for little coding overhead.  It will be much harder to take an SCE disabled application and
15582  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
15583  * for cases where you have a lot of existing code that was written before SCE was introduced and
15584  * you're migrating them a module at a time.
15585  *
15586  * That said, here's how you can completely disable SCE:
15587  *
15588  * ```
15589  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
15590  *   // Completely disable SCE.  For demonstration purposes only!
15591  *   // Do not use in new projects.
15592  *   $sceProvider.enabled(false);
15593  * });
15594  * ```
15595  *
15596  */
15597 /* jshint maxlen: 100 */
15598
15599 function $SceProvider() {
15600   var enabled = true;
15601
15602   /**
15603    * @ngdoc method
15604    * @name $sceProvider#enabled
15605    * @kind function
15606    *
15607    * @param {boolean=} value If provided, then enables/disables SCE.
15608    * @return {boolean} true if SCE is enabled, false otherwise.
15609    *
15610    * @description
15611    * Enables/disables SCE and returns the current value.
15612    */
15613   this.enabled = function(value) {
15614     if (arguments.length) {
15615       enabled = !!value;
15616     }
15617     return enabled;
15618   };
15619
15620
15621   /* Design notes on the default implementation for SCE.
15622    *
15623    * The API contract for the SCE delegate
15624    * -------------------------------------
15625    * The SCE delegate object must provide the following 3 methods:
15626    *
15627    * - trustAs(contextEnum, value)
15628    *     This method is used to tell the SCE service that the provided value is OK to use in the
15629    *     contexts specified by contextEnum.  It must return an object that will be accepted by
15630    *     getTrusted() for a compatible contextEnum and return this value.
15631    *
15632    * - valueOf(value)
15633    *     For values that were not produced by trustAs(), return them as is.  For values that were
15634    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
15635    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
15636    *     such a value.
15637    *
15638    * - getTrusted(contextEnum, value)
15639    *     This function should return the a value that is safe to use in the context specified by
15640    *     contextEnum or throw and exception otherwise.
15641    *
15642    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
15643    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
15644    * instance, an implementation could maintain a registry of all trusted objects by context.  In
15645    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
15646    * return the same object passed in if it was found in the registry under a compatible context or
15647    * throw an exception otherwise.  An implementation might only wrap values some of the time based
15648    * on some criteria.  getTrusted() might return a value and not throw an exception for special
15649    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
15650    *
15651    *
15652    * A note on the inheritance model for SCE contexts
15653    * ------------------------------------------------
15654    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
15655    * is purely an implementation details.
15656    *
15657    * The contract is simply this:
15658    *
15659    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
15660    *     will also succeed.
15661    *
15662    * Inheritance happens to capture this in a natural way.  In some future, we
15663    * may not use inheritance anymore.  That is OK because no code outside of
15664    * sce.js and sceSpecs.js would need to be aware of this detail.
15665    */
15666
15667   this.$get = ['$parse', '$sceDelegate', function(
15668                 $parse,   $sceDelegate) {
15669     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
15670     // the "expression(javascript expression)" syntax which is insecure.
15671     if (enabled && msie < 8) {
15672       throw $sceMinErr('iequirks',
15673         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
15674         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
15675         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
15676     }
15677
15678     var sce = shallowCopy(SCE_CONTEXTS);
15679
15680     /**
15681      * @ngdoc method
15682      * @name $sce#isEnabled
15683      * @kind function
15684      *
15685      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
15686      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
15687      *
15688      * @description
15689      * Returns a boolean indicating if SCE is enabled.
15690      */
15691     sce.isEnabled = function() {
15692       return enabled;
15693     };
15694     sce.trustAs = $sceDelegate.trustAs;
15695     sce.getTrusted = $sceDelegate.getTrusted;
15696     sce.valueOf = $sceDelegate.valueOf;
15697
15698     if (!enabled) {
15699       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
15700       sce.valueOf = identity;
15701     }
15702
15703     /**
15704      * @ngdoc method
15705      * @name $sce#parseAs
15706      *
15707      * @description
15708      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
15709      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
15710      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
15711      * *result*)}
15712      *
15713      * @param {string} type The kind of SCE context in which this result will be used.
15714      * @param {string} expression String expression to compile.
15715      * @returns {function(context, locals)} a function which represents the compiled expression:
15716      *
15717      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15718      *      are evaluated against (typically a scope object).
15719      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15720      *      `context`.
15721      */
15722     sce.parseAs = function sceParseAs(type, expr) {
15723       var parsed = $parse(expr);
15724       if (parsed.literal && parsed.constant) {
15725         return parsed;
15726       } else {
15727         return $parse(expr, function(value) {
15728           return sce.getTrusted(type, value);
15729         });
15730       }
15731     };
15732
15733     /**
15734      * @ngdoc method
15735      * @name $sce#trustAs
15736      *
15737      * @description
15738      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
15739      * returns an object that is trusted by angular for use in specified strict contextual
15740      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
15741      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
15742      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
15743      * escaping.
15744      *
15745      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15746      *   resource_url, html, js and css.
15747      * @param {*} value The value that that should be considered trusted/safe.
15748      * @returns {*} A value that can be used to stand in for the provided `value` in places
15749      * where Angular expects a $sce.trustAs() return value.
15750      */
15751
15752     /**
15753      * @ngdoc method
15754      * @name $sce#trustAsHtml
15755      *
15756      * @description
15757      * Shorthand method.  `$sce.trustAsHtml(value)` →
15758      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
15759      *
15760      * @param {*} value The value to trustAs.
15761      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
15762      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
15763      *     only accept expressions that are either literal constants or are the
15764      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15765      */
15766
15767     /**
15768      * @ngdoc method
15769      * @name $sce#trustAsUrl
15770      *
15771      * @description
15772      * Shorthand method.  `$sce.trustAsUrl(value)` →
15773      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
15774      *
15775      * @param {*} value The value to trustAs.
15776      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
15777      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
15778      *     only accept expressions that are either literal constants or are the
15779      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15780      */
15781
15782     /**
15783      * @ngdoc method
15784      * @name $sce#trustAsResourceUrl
15785      *
15786      * @description
15787      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
15788      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
15789      *
15790      * @param {*} value The value to trustAs.
15791      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
15792      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
15793      *     only accept expressions that are either literal constants or are the return
15794      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
15795      */
15796
15797     /**
15798      * @ngdoc method
15799      * @name $sce#trustAsJs
15800      *
15801      * @description
15802      * Shorthand method.  `$sce.trustAsJs(value)` →
15803      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
15804      *
15805      * @param {*} value The value to trustAs.
15806      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
15807      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
15808      *     only accept expressions that are either literal constants or are the
15809      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15810      */
15811
15812     /**
15813      * @ngdoc method
15814      * @name $sce#getTrusted
15815      *
15816      * @description
15817      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
15818      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
15819      * originally supplied value if the queried context type is a supertype of the created type.
15820      * If this condition isn't satisfied, throws an exception.
15821      *
15822      * @param {string} type The kind of context in which this value is to be used.
15823      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
15824      *                         call.
15825      * @returns {*} The value the was originally provided to
15826      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
15827      *              Otherwise, throws an exception.
15828      */
15829
15830     /**
15831      * @ngdoc method
15832      * @name $sce#getTrustedHtml
15833      *
15834      * @description
15835      * Shorthand method.  `$sce.getTrustedHtml(value)` →
15836      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
15837      *
15838      * @param {*} value The value to pass to `$sce.getTrusted`.
15839      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
15840      */
15841
15842     /**
15843      * @ngdoc method
15844      * @name $sce#getTrustedCss
15845      *
15846      * @description
15847      * Shorthand method.  `$sce.getTrustedCss(value)` →
15848      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
15849      *
15850      * @param {*} value The value to pass to `$sce.getTrusted`.
15851      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
15852      */
15853
15854     /**
15855      * @ngdoc method
15856      * @name $sce#getTrustedUrl
15857      *
15858      * @description
15859      * Shorthand method.  `$sce.getTrustedUrl(value)` →
15860      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
15861      *
15862      * @param {*} value The value to pass to `$sce.getTrusted`.
15863      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
15864      */
15865
15866     /**
15867      * @ngdoc method
15868      * @name $sce#getTrustedResourceUrl
15869      *
15870      * @description
15871      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
15872      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
15873      *
15874      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
15875      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
15876      */
15877
15878     /**
15879      * @ngdoc method
15880      * @name $sce#getTrustedJs
15881      *
15882      * @description
15883      * Shorthand method.  `$sce.getTrustedJs(value)` →
15884      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
15885      *
15886      * @param {*} value The value to pass to `$sce.getTrusted`.
15887      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
15888      */
15889
15890     /**
15891      * @ngdoc method
15892      * @name $sce#parseAsHtml
15893      *
15894      * @description
15895      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
15896      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
15897      *
15898      * @param {string} expression String expression to compile.
15899      * @returns {function(context, locals)} a function which represents the compiled expression:
15900      *
15901      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15902      *      are evaluated against (typically a scope object).
15903      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15904      *      `context`.
15905      */
15906
15907     /**
15908      * @ngdoc method
15909      * @name $sce#parseAsCss
15910      *
15911      * @description
15912      * Shorthand method.  `$sce.parseAsCss(value)` →
15913      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
15914      *
15915      * @param {string} expression String expression to compile.
15916      * @returns {function(context, locals)} a function which represents the compiled expression:
15917      *
15918      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15919      *      are evaluated against (typically a scope object).
15920      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15921      *      `context`.
15922      */
15923
15924     /**
15925      * @ngdoc method
15926      * @name $sce#parseAsUrl
15927      *
15928      * @description
15929      * Shorthand method.  `$sce.parseAsUrl(value)` →
15930      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
15931      *
15932      * @param {string} expression String expression to compile.
15933      * @returns {function(context, locals)} a function which represents the compiled expression:
15934      *
15935      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15936      *      are evaluated against (typically a scope object).
15937      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15938      *      `context`.
15939      */
15940
15941     /**
15942      * @ngdoc method
15943      * @name $sce#parseAsResourceUrl
15944      *
15945      * @description
15946      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
15947      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
15948      *
15949      * @param {string} expression String expression to compile.
15950      * @returns {function(context, locals)} a function which represents the compiled expression:
15951      *
15952      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15953      *      are evaluated against (typically a scope object).
15954      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15955      *      `context`.
15956      */
15957
15958     /**
15959      * @ngdoc method
15960      * @name $sce#parseAsJs
15961      *
15962      * @description
15963      * Shorthand method.  `$sce.parseAsJs(value)` →
15964      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
15965      *
15966      * @param {string} expression String expression to compile.
15967      * @returns {function(context, locals)} a function which represents the compiled expression:
15968      *
15969      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15970      *      are evaluated against (typically a scope object).
15971      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15972      *      `context`.
15973      */
15974
15975     // Shorthand delegations.
15976     var parse = sce.parseAs,
15977         getTrusted = sce.getTrusted,
15978         trustAs = sce.trustAs;
15979
15980     forEach(SCE_CONTEXTS, function(enumValue, name) {
15981       var lName = lowercase(name);
15982       sce[camelCase("parse_as_" + lName)] = function(expr) {
15983         return parse(enumValue, expr);
15984       };
15985       sce[camelCase("get_trusted_" + lName)] = function(value) {
15986         return getTrusted(enumValue, value);
15987       };
15988       sce[camelCase("trust_as_" + lName)] = function(value) {
15989         return trustAs(enumValue, value);
15990       };
15991     });
15992
15993     return sce;
15994   }];
15995 }
15996
15997 /**
15998  * !!! This is an undocumented "private" service !!!
15999  *
16000  * @name $sniffer
16001  * @requires $window
16002  * @requires $document
16003  *
16004  * @property {boolean} history Does the browser support html5 history api ?
16005  * @property {boolean} transitions Does the browser support CSS transition events ?
16006  * @property {boolean} animations Does the browser support CSS animation events ?
16007  *
16008  * @description
16009  * This is very simple implementation of testing browser's features.
16010  */
16011 function $SnifferProvider() {
16012   this.$get = ['$window', '$document', function($window, $document) {
16013     var eventSupport = {},
16014         android =
16015           int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
16016         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
16017         document = $document[0] || {},
16018         vendorPrefix,
16019         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
16020         bodyStyle = document.body && document.body.style,
16021         transitions = false,
16022         animations = false,
16023         match;
16024
16025     if (bodyStyle) {
16026       for (var prop in bodyStyle) {
16027         if (match = vendorRegex.exec(prop)) {
16028           vendorPrefix = match[0];
16029           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
16030           break;
16031         }
16032       }
16033
16034       if (!vendorPrefix) {
16035         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
16036       }
16037
16038       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
16039       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
16040
16041       if (android && (!transitions ||  !animations)) {
16042         transitions = isString(document.body.style.webkitTransition);
16043         animations = isString(document.body.style.webkitAnimation);
16044       }
16045     }
16046
16047
16048     return {
16049       // Android has history.pushState, but it does not update location correctly
16050       // so let's not use the history API at all.
16051       // http://code.google.com/p/android/issues/detail?id=17471
16052       // https://github.com/angular/angular.js/issues/904
16053
16054       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
16055       // so let's not use the history API also
16056       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
16057       // jshint -W018
16058       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
16059       // jshint +W018
16060       hasEvent: function(event) {
16061         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
16062         // it. In particular the event is not fired when backspace or delete key are pressed or
16063         // when cut operation is performed.
16064         // IE10+ implements 'input' event but it erroneously fires under various situations,
16065         // e.g. when placeholder changes, or a form is focused.
16066         if (event === 'input' && msie <= 11) return false;
16067
16068         if (isUndefined(eventSupport[event])) {
16069           var divElm = document.createElement('div');
16070           eventSupport[event] = 'on' + event in divElm;
16071         }
16072
16073         return eventSupport[event];
16074       },
16075       csp: csp(),
16076       vendorPrefix: vendorPrefix,
16077       transitions: transitions,
16078       animations: animations,
16079       android: android
16080     };
16081   }];
16082 }
16083
16084 var $compileMinErr = minErr('$compile');
16085
16086 /**
16087  * @ngdoc service
16088  * @name $templateRequest
16089  *
16090  * @description
16091  * The `$templateRequest` service downloads the provided template using `$http` and, upon success,
16092  * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
16093  * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
16094  * by setting the 2nd parameter of the function to true).
16095  *
16096  * @param {string} tpl The HTTP request template URL
16097  * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
16098  *
16099  * @return {Promise} the HTTP Promise for the given.
16100  *
16101  * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
16102  */
16103 function $TemplateRequestProvider() {
16104   this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
16105     function handleRequestFn(tpl, ignoreRequestError) {
16106       handleRequestFn.totalPendingRequests++;
16107
16108       var transformResponse = $http.defaults && $http.defaults.transformResponse;
16109
16110       if (isArray(transformResponse)) {
16111         transformResponse = transformResponse.filter(function(transformer) {
16112           return transformer !== defaultHttpResponseTransform;
16113         });
16114       } else if (transformResponse === defaultHttpResponseTransform) {
16115         transformResponse = null;
16116       }
16117
16118       var httpOptions = {
16119         cache: $templateCache,
16120         transformResponse: transformResponse
16121       };
16122
16123       return $http.get(tpl, httpOptions)
16124         ['finally'](function() {
16125           handleRequestFn.totalPendingRequests--;
16126         })
16127         .then(function(response) {
16128           return response.data;
16129         }, handleError);
16130
16131       function handleError(resp) {
16132         if (!ignoreRequestError) {
16133           throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
16134         }
16135         return $q.reject(resp);
16136       }
16137     }
16138
16139     handleRequestFn.totalPendingRequests = 0;
16140
16141     return handleRequestFn;
16142   }];
16143 }
16144
16145 function $$TestabilityProvider() {
16146   this.$get = ['$rootScope', '$browser', '$location',
16147        function($rootScope,   $browser,   $location) {
16148
16149     /**
16150      * @name $testability
16151      *
16152      * @description
16153      * The private $$testability service provides a collection of methods for use when debugging
16154      * or by automated test and debugging tools.
16155      */
16156     var testability = {};
16157
16158     /**
16159      * @name $$testability#findBindings
16160      *
16161      * @description
16162      * Returns an array of elements that are bound (via ng-bind or {{}})
16163      * to expressions matching the input.
16164      *
16165      * @param {Element} element The element root to search from.
16166      * @param {string} expression The binding expression to match.
16167      * @param {boolean} opt_exactMatch If true, only returns exact matches
16168      *     for the expression. Filters and whitespace are ignored.
16169      */
16170     testability.findBindings = function(element, expression, opt_exactMatch) {
16171       var bindings = element.getElementsByClassName('ng-binding');
16172       var matches = [];
16173       forEach(bindings, function(binding) {
16174         var dataBinding = angular.element(binding).data('$binding');
16175         if (dataBinding) {
16176           forEach(dataBinding, function(bindingName) {
16177             if (opt_exactMatch) {
16178               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
16179               if (matcher.test(bindingName)) {
16180                 matches.push(binding);
16181               }
16182             } else {
16183               if (bindingName.indexOf(expression) != -1) {
16184                 matches.push(binding);
16185               }
16186             }
16187           });
16188         }
16189       });
16190       return matches;
16191     };
16192
16193     /**
16194      * @name $$testability#findModels
16195      *
16196      * @description
16197      * Returns an array of elements that are two-way found via ng-model to
16198      * expressions matching the input.
16199      *
16200      * @param {Element} element The element root to search from.
16201      * @param {string} expression The model expression to match.
16202      * @param {boolean} opt_exactMatch If true, only returns exact matches
16203      *     for the expression.
16204      */
16205     testability.findModels = function(element, expression, opt_exactMatch) {
16206       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
16207       for (var p = 0; p < prefixes.length; ++p) {
16208         var attributeEquals = opt_exactMatch ? '=' : '*=';
16209         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
16210         var elements = element.querySelectorAll(selector);
16211         if (elements.length) {
16212           return elements;
16213         }
16214       }
16215     };
16216
16217     /**
16218      * @name $$testability#getLocation
16219      *
16220      * @description
16221      * Shortcut for getting the location in a browser agnostic way. Returns
16222      *     the path, search, and hash. (e.g. /path?a=b#hash)
16223      */
16224     testability.getLocation = function() {
16225       return $location.url();
16226     };
16227
16228     /**
16229      * @name $$testability#setLocation
16230      *
16231      * @description
16232      * Shortcut for navigating to a location without doing a full page reload.
16233      *
16234      * @param {string} url The location url (path, search and hash,
16235      *     e.g. /path?a=b#hash) to go to.
16236      */
16237     testability.setLocation = function(url) {
16238       if (url !== $location.url()) {
16239         $location.url(url);
16240         $rootScope.$digest();
16241       }
16242     };
16243
16244     /**
16245      * @name $$testability#whenStable
16246      *
16247      * @description
16248      * Calls the callback when $timeout and $http requests are completed.
16249      *
16250      * @param {function} callback
16251      */
16252     testability.whenStable = function(callback) {
16253       $browser.notifyWhenNoOutstandingRequests(callback);
16254     };
16255
16256     return testability;
16257   }];
16258 }
16259
16260 function $TimeoutProvider() {
16261   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
16262        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
16263     var deferreds = {};
16264
16265
16266      /**
16267       * @ngdoc service
16268       * @name $timeout
16269       *
16270       * @description
16271       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
16272       * block and delegates any exceptions to
16273       * {@link ng.$exceptionHandler $exceptionHandler} service.
16274       *
16275       * The return value of registering a timeout function is a promise, which will be resolved when
16276       * the timeout is reached and the timeout function is executed.
16277       *
16278       * To cancel a timeout request, call `$timeout.cancel(promise)`.
16279       *
16280       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
16281       * synchronously flush the queue of deferred functions.
16282       *
16283       * @param {function()} fn A function, whose execution should be delayed.
16284       * @param {number=} [delay=0] Delay in milliseconds.
16285       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
16286       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
16287       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
16288       *   promise will be resolved with is the return value of the `fn` function.
16289       *
16290       */
16291     function timeout(fn, delay, invokeApply) {
16292       var skipApply = (isDefined(invokeApply) && !invokeApply),
16293           deferred = (skipApply ? $$q : $q).defer(),
16294           promise = deferred.promise,
16295           timeoutId;
16296
16297       timeoutId = $browser.defer(function() {
16298         try {
16299           deferred.resolve(fn());
16300         } catch (e) {
16301           deferred.reject(e);
16302           $exceptionHandler(e);
16303         }
16304         finally {
16305           delete deferreds[promise.$$timeoutId];
16306         }
16307
16308         if (!skipApply) $rootScope.$apply();
16309       }, delay);
16310
16311       promise.$$timeoutId = timeoutId;
16312       deferreds[timeoutId] = deferred;
16313
16314       return promise;
16315     }
16316
16317
16318      /**
16319       * @ngdoc method
16320       * @name $timeout#cancel
16321       *
16322       * @description
16323       * Cancels a task associated with the `promise`. As a result of this, the promise will be
16324       * resolved with a rejection.
16325       *
16326       * @param {Promise=} promise Promise returned by the `$timeout` function.
16327       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
16328       *   canceled.
16329       */
16330     timeout.cancel = function(promise) {
16331       if (promise && promise.$$timeoutId in deferreds) {
16332         deferreds[promise.$$timeoutId].reject('canceled');
16333         delete deferreds[promise.$$timeoutId];
16334         return $browser.defer.cancel(promise.$$timeoutId);
16335       }
16336       return false;
16337     };
16338
16339     return timeout;
16340   }];
16341 }
16342
16343 // NOTE:  The usage of window and document instead of $window and $document here is
16344 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
16345 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
16346 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
16347 // doesn't know about mocked locations and resolves URLs to the real document - which is
16348 // exactly the behavior needed here.  There is little value is mocking these out for this
16349 // service.
16350 var urlParsingNode = document.createElement("a");
16351 var originUrl = urlResolve(window.location.href);
16352
16353
16354 /**
16355  *
16356  * Implementation Notes for non-IE browsers
16357  * ----------------------------------------
16358  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
16359  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
16360  * URL will be resolved into an absolute URL in the context of the application document.
16361  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
16362  * properties are all populated to reflect the normalized URL.  This approach has wide
16363  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
16364  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16365  *
16366  * Implementation Notes for IE
16367  * ---------------------------
16368  * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
16369  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
16370  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
16371  * work around that by performing the parsing in a 2nd step by taking a previously normalized
16372  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
16373  * properties such as protocol, hostname, port, etc.
16374  *
16375  * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
16376  * uses the inner HTML approach to assign the URL as part of an HTML snippet -
16377  * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
16378  * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
16379  * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
16380  * method and IE < 8 is unsupported.
16381  *
16382  * References:
16383  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
16384  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16385  *   http://url.spec.whatwg.org/#urlutils
16386  *   https://github.com/angular/angular.js/pull/2902
16387  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
16388  *
16389  * @kind function
16390  * @param {string} url The URL to be parsed.
16391  * @description Normalizes and parses a URL.
16392  * @returns {object} Returns the normalized URL as a dictionary.
16393  *
16394  *   | member name   | Description    |
16395  *   |---------------|----------------|
16396  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
16397  *   | protocol      | The protocol including the trailing colon                              |
16398  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
16399  *   | search        | The search params, minus the question mark                             |
16400  *   | hash          | The hash string, minus the hash symbol
16401  *   | hostname      | The hostname
16402  *   | port          | The port, without ":"
16403  *   | pathname      | The pathname, beginning with "/"
16404  *
16405  */
16406 function urlResolve(url) {
16407   var href = url;
16408
16409   if (msie) {
16410     // Normalize before parse.  Refer Implementation Notes on why this is
16411     // done in two steps on IE.
16412     urlParsingNode.setAttribute("href", href);
16413     href = urlParsingNode.href;
16414   }
16415
16416   urlParsingNode.setAttribute('href', href);
16417
16418   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
16419   return {
16420     href: urlParsingNode.href,
16421     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
16422     host: urlParsingNode.host,
16423     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
16424     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
16425     hostname: urlParsingNode.hostname,
16426     port: urlParsingNode.port,
16427     pathname: (urlParsingNode.pathname.charAt(0) === '/')
16428       ? urlParsingNode.pathname
16429       : '/' + urlParsingNode.pathname
16430   };
16431 }
16432
16433 /**
16434  * Parse a request URL and determine whether this is a same-origin request as the application document.
16435  *
16436  * @param {string|object} requestUrl The url of the request as a string that will be resolved
16437  * or a parsed URL object.
16438  * @returns {boolean} Whether the request is for the same origin as the application document.
16439  */
16440 function urlIsSameOrigin(requestUrl) {
16441   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
16442   return (parsed.protocol === originUrl.protocol &&
16443           parsed.host === originUrl.host);
16444 }
16445
16446 /**
16447  * @ngdoc service
16448  * @name $window
16449  *
16450  * @description
16451  * A reference to the browser's `window` object. While `window`
16452  * is globally available in JavaScript, it causes testability problems, because
16453  * it is a global variable. In angular we always refer to it through the
16454  * `$window` service, so it may be overridden, removed or mocked for testing.
16455  *
16456  * Expressions, like the one defined for the `ngClick` directive in the example
16457  * below, are evaluated with respect to the current scope.  Therefore, there is
16458  * no risk of inadvertently coding in a dependency on a global value in such an
16459  * expression.
16460  *
16461  * @example
16462    <example module="windowExample">
16463      <file name="index.html">
16464        <script>
16465          angular.module('windowExample', [])
16466            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
16467              $scope.greeting = 'Hello, World!';
16468              $scope.doGreeting = function(greeting) {
16469                $window.alert(greeting);
16470              };
16471            }]);
16472        </script>
16473        <div ng-controller="ExampleController">
16474          <input type="text" ng-model="greeting" />
16475          <button ng-click="doGreeting(greeting)">ALERT</button>
16476        </div>
16477      </file>
16478      <file name="protractor.js" type="protractor">
16479       it('should display the greeting in the input box', function() {
16480        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
16481        // If we click the button it will block the test runner
16482        // element(':button').click();
16483       });
16484      </file>
16485    </example>
16486  */
16487 function $WindowProvider() {
16488   this.$get = valueFn(window);
16489 }
16490
16491 /* global currencyFilter: true,
16492  dateFilter: true,
16493  filterFilter: true,
16494  jsonFilter: true,
16495  limitToFilter: true,
16496  lowercaseFilter: true,
16497  numberFilter: true,
16498  orderByFilter: true,
16499  uppercaseFilter: true,
16500  */
16501
16502 /**
16503  * @ngdoc provider
16504  * @name $filterProvider
16505  * @description
16506  *
16507  * Filters are just functions which transform input to an output. However filters need to be
16508  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
16509  * annotated with dependencies and is responsible for creating a filter function.
16510  *
16511  * ```js
16512  *   // Filter registration
16513  *   function MyModule($provide, $filterProvider) {
16514  *     // create a service to demonstrate injection (not always needed)
16515  *     $provide.value('greet', function(name){
16516  *       return 'Hello ' + name + '!';
16517  *     });
16518  *
16519  *     // register a filter factory which uses the
16520  *     // greet service to demonstrate DI.
16521  *     $filterProvider.register('greet', function(greet){
16522  *       // return the filter function which uses the greet service
16523  *       // to generate salutation
16524  *       return function(text) {
16525  *         // filters need to be forgiving so check input validity
16526  *         return text && greet(text) || text;
16527  *       };
16528  *     });
16529  *   }
16530  * ```
16531  *
16532  * The filter function is registered with the `$injector` under the filter name suffix with
16533  * `Filter`.
16534  *
16535  * ```js
16536  *   it('should be the same instance', inject(
16537  *     function($filterProvider) {
16538  *       $filterProvider.register('reverse', function(){
16539  *         return ...;
16540  *       });
16541  *     },
16542  *     function($filter, reverseFilter) {
16543  *       expect($filter('reverse')).toBe(reverseFilter);
16544  *     });
16545  * ```
16546  *
16547  *
16548  * For more information about how angular filters work, and how to create your own filters, see
16549  * {@link guide/filter Filters} in the Angular Developer Guide.
16550  */
16551
16552 /**
16553  * @ngdoc service
16554  * @name $filter
16555  * @kind function
16556  * @description
16557  * Filters are used for formatting data displayed to the user.
16558  *
16559  * The general syntax in templates is as follows:
16560  *
16561  *         {{ expression [| filter_name[:parameter_value] ... ] }}
16562  *
16563  * @param {String} name Name of the filter function to retrieve
16564  * @return {Function} the filter function
16565  * @example
16566    <example name="$filter" module="filterExample">
16567      <file name="index.html">
16568        <div ng-controller="MainCtrl">
16569         <h3>{{ originalText }}</h3>
16570         <h3>{{ filteredText }}</h3>
16571        </div>
16572      </file>
16573
16574      <file name="script.js">
16575       angular.module('filterExample', [])
16576       .controller('MainCtrl', function($scope, $filter) {
16577         $scope.originalText = 'hello';
16578         $scope.filteredText = $filter('uppercase')($scope.originalText);
16579       });
16580      </file>
16581    </example>
16582   */
16583 $FilterProvider.$inject = ['$provide'];
16584 function $FilterProvider($provide) {
16585   var suffix = 'Filter';
16586
16587   /**
16588    * @ngdoc method
16589    * @name $filterProvider#register
16590    * @param {string|Object} name Name of the filter function, or an object map of filters where
16591    *    the keys are the filter names and the values are the filter factories.
16592    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
16593    *    of the registered filter instances.
16594    */
16595   function register(name, factory) {
16596     if (isObject(name)) {
16597       var filters = {};
16598       forEach(name, function(filter, key) {
16599         filters[key] = register(key, filter);
16600       });
16601       return filters;
16602     } else {
16603       return $provide.factory(name + suffix, factory);
16604     }
16605   }
16606   this.register = register;
16607
16608   this.$get = ['$injector', function($injector) {
16609     return function(name) {
16610       return $injector.get(name + suffix);
16611     };
16612   }];
16613
16614   ////////////////////////////////////////
16615
16616   /* global
16617     currencyFilter: false,
16618     dateFilter: false,
16619     filterFilter: false,
16620     jsonFilter: false,
16621     limitToFilter: false,
16622     lowercaseFilter: false,
16623     numberFilter: false,
16624     orderByFilter: false,
16625     uppercaseFilter: false,
16626   */
16627
16628   register('currency', currencyFilter);
16629   register('date', dateFilter);
16630   register('filter', filterFilter);
16631   register('json', jsonFilter);
16632   register('limitTo', limitToFilter);
16633   register('lowercase', lowercaseFilter);
16634   register('number', numberFilter);
16635   register('orderBy', orderByFilter);
16636   register('uppercase', uppercaseFilter);
16637 }
16638
16639 /**
16640  * @ngdoc filter
16641  * @name filter
16642  * @kind function
16643  *
16644  * @description
16645  * Selects a subset of items from `array` and returns it as a new array.
16646  *
16647  * @param {Array} array The source array.
16648  * @param {string|Object|function()} expression The predicate to be used for selecting items from
16649  *   `array`.
16650  *
16651  *   Can be one of:
16652  *
16653  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
16654  *     objects with string properties in `array` that match this string will be returned. This also
16655  *     applies to nested object properties.
16656  *     The predicate can be negated by prefixing the string with `!`.
16657  *
16658  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
16659  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
16660  *     which have property `name` containing "M" and property `phone` containing "1". A special
16661  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
16662  *     property of the object or its nested object properties. That's equivalent to the simple
16663  *     substring match with a `string` as described above. The predicate can be negated by prefixing
16664  *     the string with `!`.
16665  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
16666  *     not containing "M".
16667  *
16668  *     Note that a named property will match properties on the same level only, while the special
16669  *     `$` property will match properties on the same level or deeper. E.g. an array item like
16670  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
16671  *     **will** be matched by `{$: 'John'}`.
16672  *
16673  *   - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
16674  *     function is called for each element of `array`. The final result is an array of those
16675  *     elements that the predicate returned true for.
16676  *
16677  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
16678  *     determining if the expected value (from the filter expression) and actual value (from
16679  *     the object in the array) should be considered a match.
16680  *
16681  *   Can be one of:
16682  *
16683  *   - `function(actual, expected)`:
16684  *     The function will be given the object value and the predicate value to compare and
16685  *     should return true if both values should be considered equal.
16686  *
16687  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
16688  *     This is essentially strict comparison of expected and actual.
16689  *
16690  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
16691  *     insensitive way.
16692  *
16693  * @example
16694    <example>
16695      <file name="index.html">
16696        <div ng-init="friends = [{name:'John', phone:'555-1276'},
16697                                 {name:'Mary', phone:'800-BIG-MARY'},
16698                                 {name:'Mike', phone:'555-4321'},
16699                                 {name:'Adam', phone:'555-5678'},
16700                                 {name:'Julie', phone:'555-8765'},
16701                                 {name:'Juliette', phone:'555-5678'}]"></div>
16702
16703        Search: <input ng-model="searchText">
16704        <table id="searchTextResults">
16705          <tr><th>Name</th><th>Phone</th></tr>
16706          <tr ng-repeat="friend in friends | filter:searchText">
16707            <td>{{friend.name}}</td>
16708            <td>{{friend.phone}}</td>
16709          </tr>
16710        </table>
16711        <hr>
16712        Any: <input ng-model="search.$"> <br>
16713        Name only <input ng-model="search.name"><br>
16714        Phone only <input ng-model="search.phone"><br>
16715        Equality <input type="checkbox" ng-model="strict"><br>
16716        <table id="searchObjResults">
16717          <tr><th>Name</th><th>Phone</th></tr>
16718          <tr ng-repeat="friendObj in friends | filter:search:strict">
16719            <td>{{friendObj.name}}</td>
16720            <td>{{friendObj.phone}}</td>
16721          </tr>
16722        </table>
16723      </file>
16724      <file name="protractor.js" type="protractor">
16725        var expectFriendNames = function(expectedNames, key) {
16726          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
16727            arr.forEach(function(wd, i) {
16728              expect(wd.getText()).toMatch(expectedNames[i]);
16729            });
16730          });
16731        };
16732
16733        it('should search across all fields when filtering with a string', function() {
16734          var searchText = element(by.model('searchText'));
16735          searchText.clear();
16736          searchText.sendKeys('m');
16737          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
16738
16739          searchText.clear();
16740          searchText.sendKeys('76');
16741          expectFriendNames(['John', 'Julie'], 'friend');
16742        });
16743
16744        it('should search in specific fields when filtering with a predicate object', function() {
16745          var searchAny = element(by.model('search.$'));
16746          searchAny.clear();
16747          searchAny.sendKeys('i');
16748          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
16749        });
16750        it('should use a equal comparison when comparator is true', function() {
16751          var searchName = element(by.model('search.name'));
16752          var strict = element(by.model('strict'));
16753          searchName.clear();
16754          searchName.sendKeys('Julie');
16755          strict.click();
16756          expectFriendNames(['Julie'], 'friendObj');
16757        });
16758      </file>
16759    </example>
16760  */
16761 function filterFilter() {
16762   return function(array, expression, comparator) {
16763     if (!isArray(array)) return array;
16764
16765     var predicateFn;
16766     var matchAgainstAnyProp;
16767
16768     switch (typeof expression) {
16769       case 'function':
16770         predicateFn = expression;
16771         break;
16772       case 'boolean':
16773       case 'number':
16774       case 'string':
16775         matchAgainstAnyProp = true;
16776         //jshint -W086
16777       case 'object':
16778         //jshint +W086
16779         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
16780         break;
16781       default:
16782         return array;
16783     }
16784
16785     return array.filter(predicateFn);
16786   };
16787 }
16788
16789 // Helper functions for `filterFilter`
16790 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
16791   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
16792   var predicateFn;
16793
16794   if (comparator === true) {
16795     comparator = equals;
16796   } else if (!isFunction(comparator)) {
16797     comparator = function(actual, expected) {
16798       if (isObject(actual) || isObject(expected)) {
16799         // Prevent an object to be considered equal to a string like `'[object'`
16800         return false;
16801       }
16802
16803       actual = lowercase('' + actual);
16804       expected = lowercase('' + expected);
16805       return actual.indexOf(expected) !== -1;
16806     };
16807   }
16808
16809   predicateFn = function(item) {
16810     if (shouldMatchPrimitives && !isObject(item)) {
16811       return deepCompare(item, expression.$, comparator, false);
16812     }
16813     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
16814   };
16815
16816   return predicateFn;
16817 }
16818
16819 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
16820   var actualType = (actual !== null) ? typeof actual : 'null';
16821   var expectedType = (expected !== null) ? typeof expected : 'null';
16822
16823   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
16824     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
16825   } else if (isArray(actual)) {
16826     // In case `actual` is an array, consider it a match
16827     // if ANY of it's items matches `expected`
16828     return actual.some(function(item) {
16829       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
16830     });
16831   }
16832
16833   switch (actualType) {
16834     case 'object':
16835       var key;
16836       if (matchAgainstAnyProp) {
16837         for (key in actual) {
16838           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
16839             return true;
16840           }
16841         }
16842         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
16843       } else if (expectedType === 'object') {
16844         for (key in expected) {
16845           var expectedVal = expected[key];
16846           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
16847             continue;
16848           }
16849
16850           var matchAnyProperty = key === '$';
16851           var actualVal = matchAnyProperty ? actual : actual[key];
16852           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
16853             return false;
16854           }
16855         }
16856         return true;
16857       } else {
16858         return comparator(actual, expected);
16859       }
16860       break;
16861     case 'function':
16862       return false;
16863     default:
16864       return comparator(actual, expected);
16865   }
16866 }
16867
16868 /**
16869  * @ngdoc filter
16870  * @name currency
16871  * @kind function
16872  *
16873  * @description
16874  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
16875  * symbol for current locale is used.
16876  *
16877  * @param {number} amount Input to filter.
16878  * @param {string=} symbol Currency symbol or identifier to be displayed.
16879  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
16880  * @returns {string} Formatted number.
16881  *
16882  *
16883  * @example
16884    <example module="currencyExample">
16885      <file name="index.html">
16886        <script>
16887          angular.module('currencyExample', [])
16888            .controller('ExampleController', ['$scope', function($scope) {
16889              $scope.amount = 1234.56;
16890            }]);
16891        </script>
16892        <div ng-controller="ExampleController">
16893          <input type="number" ng-model="amount"> <br>
16894          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
16895          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
16896          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
16897        </div>
16898      </file>
16899      <file name="protractor.js" type="protractor">
16900        it('should init with 1234.56', function() {
16901          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
16902          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
16903          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
16904        });
16905        it('should update', function() {
16906          if (browser.params.browser == 'safari') {
16907            // Safari does not understand the minus key. See
16908            // https://github.com/angular/protractor/issues/481
16909            return;
16910          }
16911          element(by.model('amount')).clear();
16912          element(by.model('amount')).sendKeys('-1234');
16913          expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
16914          expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
16915          expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
16916        });
16917      </file>
16918    </example>
16919  */
16920 currencyFilter.$inject = ['$locale'];
16921 function currencyFilter($locale) {
16922   var formats = $locale.NUMBER_FORMATS;
16923   return function(amount, currencySymbol, fractionSize) {
16924     if (isUndefined(currencySymbol)) {
16925       currencySymbol = formats.CURRENCY_SYM;
16926     }
16927
16928     if (isUndefined(fractionSize)) {
16929       fractionSize = formats.PATTERNS[1].maxFrac;
16930     }
16931
16932     // if null or undefined pass it through
16933     return (amount == null)
16934         ? amount
16935         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
16936             replace(/\u00A4/g, currencySymbol);
16937   };
16938 }
16939
16940 /**
16941  * @ngdoc filter
16942  * @name number
16943  * @kind function
16944  *
16945  * @description
16946  * Formats a number as text.
16947  *
16948  * If the input is not a number an empty string is returned.
16949  *
16950  * @param {number|string} number Number to format.
16951  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
16952  * If this is not provided then the fraction size is computed from the current locale's number
16953  * formatting pattern. In the case of the default locale, it will be 3.
16954  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
16955  *
16956  * @example
16957    <example module="numberFilterExample">
16958      <file name="index.html">
16959        <script>
16960          angular.module('numberFilterExample', [])
16961            .controller('ExampleController', ['$scope', function($scope) {
16962              $scope.val = 1234.56789;
16963            }]);
16964        </script>
16965        <div ng-controller="ExampleController">
16966          Enter number: <input ng-model='val'><br>
16967          Default formatting: <span id='number-default'>{{val | number}}</span><br>
16968          No fractions: <span>{{val | number:0}}</span><br>
16969          Negative number: <span>{{-val | number:4}}</span>
16970        </div>
16971      </file>
16972      <file name="protractor.js" type="protractor">
16973        it('should format numbers', function() {
16974          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
16975          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
16976          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
16977        });
16978
16979        it('should update', function() {
16980          element(by.model('val')).clear();
16981          element(by.model('val')).sendKeys('3374.333');
16982          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
16983          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
16984          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
16985       });
16986      </file>
16987    </example>
16988  */
16989
16990
16991 numberFilter.$inject = ['$locale'];
16992 function numberFilter($locale) {
16993   var formats = $locale.NUMBER_FORMATS;
16994   return function(number, fractionSize) {
16995
16996     // if null or undefined pass it through
16997     return (number == null)
16998         ? number
16999         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
17000                        fractionSize);
17001   };
17002 }
17003
17004 var DECIMAL_SEP = '.';
17005 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
17006   if (!isFinite(number) || isObject(number)) return '';
17007
17008   var isNegative = number < 0;
17009   number = Math.abs(number);
17010   var numStr = number + '',
17011       formatedText = '',
17012       parts = [];
17013
17014   var hasExponent = false;
17015   if (numStr.indexOf('e') !== -1) {
17016     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
17017     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
17018       number = 0;
17019     } else {
17020       formatedText = numStr;
17021       hasExponent = true;
17022     }
17023   }
17024
17025   if (!hasExponent) {
17026     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
17027
17028     // determine fractionSize if it is not specified
17029     if (isUndefined(fractionSize)) {
17030       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
17031     }
17032
17033     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
17034     // inspired by:
17035     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
17036     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
17037
17038     var fraction = ('' + number).split(DECIMAL_SEP);
17039     var whole = fraction[0];
17040     fraction = fraction[1] || '';
17041
17042     var i, pos = 0,
17043         lgroup = pattern.lgSize,
17044         group = pattern.gSize;
17045
17046     if (whole.length >= (lgroup + group)) {
17047       pos = whole.length - lgroup;
17048       for (i = 0; i < pos; i++) {
17049         if ((pos - i) % group === 0 && i !== 0) {
17050           formatedText += groupSep;
17051         }
17052         formatedText += whole.charAt(i);
17053       }
17054     }
17055
17056     for (i = pos; i < whole.length; i++) {
17057       if ((whole.length - i) % lgroup === 0 && i !== 0) {
17058         formatedText += groupSep;
17059       }
17060       formatedText += whole.charAt(i);
17061     }
17062
17063     // format fraction part.
17064     while (fraction.length < fractionSize) {
17065       fraction += '0';
17066     }
17067
17068     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
17069   } else {
17070     if (fractionSize > 0 && number < 1) {
17071       formatedText = number.toFixed(fractionSize);
17072       number = parseFloat(formatedText);
17073     }
17074   }
17075
17076   if (number === 0) {
17077     isNegative = false;
17078   }
17079
17080   parts.push(isNegative ? pattern.negPre : pattern.posPre,
17081              formatedText,
17082              isNegative ? pattern.negSuf : pattern.posSuf);
17083   return parts.join('');
17084 }
17085
17086 function padNumber(num, digits, trim) {
17087   var neg = '';
17088   if (num < 0) {
17089     neg =  '-';
17090     num = -num;
17091   }
17092   num = '' + num;
17093   while (num.length < digits) num = '0' + num;
17094   if (trim)
17095     num = num.substr(num.length - digits);
17096   return neg + num;
17097 }
17098
17099
17100 function dateGetter(name, size, offset, trim) {
17101   offset = offset || 0;
17102   return function(date) {
17103     var value = date['get' + name]();
17104     if (offset > 0 || value > -offset)
17105       value += offset;
17106     if (value === 0 && offset == -12) value = 12;
17107     return padNumber(value, size, trim);
17108   };
17109 }
17110
17111 function dateStrGetter(name, shortForm) {
17112   return function(date, formats) {
17113     var value = date['get' + name]();
17114     var get = uppercase(shortForm ? ('SHORT' + name) : name);
17115
17116     return formats[get][value];
17117   };
17118 }
17119
17120 function timeZoneGetter(date) {
17121   var zone = -1 * date.getTimezoneOffset();
17122   var paddedZone = (zone >= 0) ? "+" : "";
17123
17124   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
17125                 padNumber(Math.abs(zone % 60), 2);
17126
17127   return paddedZone;
17128 }
17129
17130 function getFirstThursdayOfYear(year) {
17131     // 0 = index of January
17132     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
17133     // 4 = index of Thursday (+1 to account for 1st = 5)
17134     // 11 = index of *next* Thursday (+1 account for 1st = 12)
17135     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
17136 }
17137
17138 function getThursdayThisWeek(datetime) {
17139     return new Date(datetime.getFullYear(), datetime.getMonth(),
17140       // 4 = index of Thursday
17141       datetime.getDate() + (4 - datetime.getDay()));
17142 }
17143
17144 function weekGetter(size) {
17145    return function(date) {
17146       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
17147          thisThurs = getThursdayThisWeek(date);
17148
17149       var diff = +thisThurs - +firstThurs,
17150          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
17151
17152       return padNumber(result, size);
17153    };
17154 }
17155
17156 function ampmGetter(date, formats) {
17157   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
17158 }
17159
17160 function eraGetter(date, formats) {
17161   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
17162 }
17163
17164 function longEraGetter(date, formats) {
17165   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
17166 }
17167
17168 var DATE_FORMATS = {
17169   yyyy: dateGetter('FullYear', 4),
17170     yy: dateGetter('FullYear', 2, 0, true),
17171      y: dateGetter('FullYear', 1),
17172   MMMM: dateStrGetter('Month'),
17173    MMM: dateStrGetter('Month', true),
17174     MM: dateGetter('Month', 2, 1),
17175      M: dateGetter('Month', 1, 1),
17176     dd: dateGetter('Date', 2),
17177      d: dateGetter('Date', 1),
17178     HH: dateGetter('Hours', 2),
17179      H: dateGetter('Hours', 1),
17180     hh: dateGetter('Hours', 2, -12),
17181      h: dateGetter('Hours', 1, -12),
17182     mm: dateGetter('Minutes', 2),
17183      m: dateGetter('Minutes', 1),
17184     ss: dateGetter('Seconds', 2),
17185      s: dateGetter('Seconds', 1),
17186      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
17187      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
17188    sss: dateGetter('Milliseconds', 3),
17189   EEEE: dateStrGetter('Day'),
17190    EEE: dateStrGetter('Day', true),
17191      a: ampmGetter,
17192      Z: timeZoneGetter,
17193     ww: weekGetter(2),
17194      w: weekGetter(1),
17195      G: eraGetter,
17196      GG: eraGetter,
17197      GGG: eraGetter,
17198      GGGG: longEraGetter
17199 };
17200
17201 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
17202     NUMBER_STRING = /^\-?\d+$/;
17203
17204 /**
17205  * @ngdoc filter
17206  * @name date
17207  * @kind function
17208  *
17209  * @description
17210  *   Formats `date` to a string based on the requested `format`.
17211  *
17212  *   `format` string can be composed of the following elements:
17213  *
17214  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
17215  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
17216  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
17217  *   * `'MMMM'`: Month in year (January-December)
17218  *   * `'MMM'`: Month in year (Jan-Dec)
17219  *   * `'MM'`: Month in year, padded (01-12)
17220  *   * `'M'`: Month in year (1-12)
17221  *   * `'dd'`: Day in month, padded (01-31)
17222  *   * `'d'`: Day in month (1-31)
17223  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
17224  *   * `'EEE'`: Day in Week, (Sun-Sat)
17225  *   * `'HH'`: Hour in day, padded (00-23)
17226  *   * `'H'`: Hour in day (0-23)
17227  *   * `'hh'`: Hour in AM/PM, padded (01-12)
17228  *   * `'h'`: Hour in AM/PM, (1-12)
17229  *   * `'mm'`: Minute in hour, padded (00-59)
17230  *   * `'m'`: Minute in hour (0-59)
17231  *   * `'ss'`: Second in minute, padded (00-59)
17232  *   * `'s'`: Second in minute (0-59)
17233  *   * `'sss'`: Millisecond in second, padded (000-999)
17234  *   * `'a'`: AM/PM marker
17235  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
17236  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
17237  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
17238  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
17239  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
17240  *
17241  *   `format` string can also be one of the following predefined
17242  *   {@link guide/i18n localizable formats}:
17243  *
17244  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
17245  *     (e.g. Sep 3, 2010 12:05:08 PM)
17246  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
17247  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
17248  *     (e.g. Friday, September 3, 2010)
17249  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
17250  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
17251  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
17252  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
17253  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
17254  *
17255  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
17256  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
17257  *   (e.g. `"h 'o''clock'"`).
17258  *
17259  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
17260  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
17261  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
17262  *    specified in the string input, the time is considered to be in the local timezone.
17263  * @param {string=} format Formatting rules (see Description). If not specified,
17264  *    `mediumDate` is used.
17265  * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported.
17266  *    If not specified, the timezone of the browser will be used.
17267  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
17268  *
17269  * @example
17270    <example>
17271      <file name="index.html">
17272        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
17273            <span>{{1288323623006 | date:'medium'}}</span><br>
17274        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
17275           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
17276        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
17277           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
17278        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
17279           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
17280      </file>
17281      <file name="protractor.js" type="protractor">
17282        it('should format date', function() {
17283          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
17284             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
17285          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
17286             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
17287          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
17288             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
17289          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
17290             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
17291        });
17292      </file>
17293    </example>
17294  */
17295 dateFilter.$inject = ['$locale'];
17296 function dateFilter($locale) {
17297
17298
17299   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
17300                      // 1        2       3         4          5          6          7          8  9     10      11
17301   function jsonStringToDate(string) {
17302     var match;
17303     if (match = string.match(R_ISO8601_STR)) {
17304       var date = new Date(0),
17305           tzHour = 0,
17306           tzMin  = 0,
17307           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
17308           timeSetter = match[8] ? date.setUTCHours : date.setHours;
17309
17310       if (match[9]) {
17311         tzHour = int(match[9] + match[10]);
17312         tzMin = int(match[9] + match[11]);
17313       }
17314       dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
17315       var h = int(match[4] || 0) - tzHour;
17316       var m = int(match[5] || 0) - tzMin;
17317       var s = int(match[6] || 0);
17318       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
17319       timeSetter.call(date, h, m, s, ms);
17320       return date;
17321     }
17322     return string;
17323   }
17324
17325
17326   return function(date, format, timezone) {
17327     var text = '',
17328         parts = [],
17329         fn, match;
17330
17331     format = format || 'mediumDate';
17332     format = $locale.DATETIME_FORMATS[format] || format;
17333     if (isString(date)) {
17334       date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
17335     }
17336
17337     if (isNumber(date)) {
17338       date = new Date(date);
17339     }
17340
17341     if (!isDate(date)) {
17342       return date;
17343     }
17344
17345     while (format) {
17346       match = DATE_FORMATS_SPLIT.exec(format);
17347       if (match) {
17348         parts = concat(parts, match, 1);
17349         format = parts.pop();
17350       } else {
17351         parts.push(format);
17352         format = null;
17353       }
17354     }
17355
17356     if (timezone && timezone === 'UTC') {
17357       date = new Date(date.getTime());
17358       date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
17359     }
17360     forEach(parts, function(value) {
17361       fn = DATE_FORMATS[value];
17362       text += fn ? fn(date, $locale.DATETIME_FORMATS)
17363                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
17364     });
17365
17366     return text;
17367   };
17368 }
17369
17370
17371 /**
17372  * @ngdoc filter
17373  * @name json
17374  * @kind function
17375  *
17376  * @description
17377  *   Allows you to convert a JavaScript object into JSON string.
17378  *
17379  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
17380  *   the binding is automatically converted to JSON.
17381  *
17382  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
17383  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
17384  * @returns {string} JSON string.
17385  *
17386  *
17387  * @example
17388    <example>
17389      <file name="index.html">
17390        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
17391        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
17392      </file>
17393      <file name="protractor.js" type="protractor">
17394        it('should jsonify filtered objects', function() {
17395          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
17396          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
17397        });
17398      </file>
17399    </example>
17400  *
17401  */
17402 function jsonFilter() {
17403   return function(object, spacing) {
17404     if (isUndefined(spacing)) {
17405         spacing = 2;
17406     }
17407     return toJson(object, spacing);
17408   };
17409 }
17410
17411
17412 /**
17413  * @ngdoc filter
17414  * @name lowercase
17415  * @kind function
17416  * @description
17417  * Converts string to lowercase.
17418  * @see angular.lowercase
17419  */
17420 var lowercaseFilter = valueFn(lowercase);
17421
17422
17423 /**
17424  * @ngdoc filter
17425  * @name uppercase
17426  * @kind function
17427  * @description
17428  * Converts string to uppercase.
17429  * @see angular.uppercase
17430  */
17431 var uppercaseFilter = valueFn(uppercase);
17432
17433 /**
17434  * @ngdoc filter
17435  * @name limitTo
17436  * @kind function
17437  *
17438  * @description
17439  * Creates a new array or string containing only a specified number of elements. The elements
17440  * are taken from either the beginning or the end of the source array, string or number, as specified by
17441  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
17442  * converted to a string.
17443  *
17444  * @param {Array|string|number} input Source array, string or number to be limited.
17445  * @param {string|number} limit The length of the returned array or string. If the `limit` number
17446  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
17447  *     If the number is negative, `limit` number  of items from the end of the source array/string
17448  *     are copied. The `limit` will be trimmed if it exceeds `array.length`
17449  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
17450  *     had less than `limit` elements.
17451  *
17452  * @example
17453    <example module="limitToExample">
17454      <file name="index.html">
17455        <script>
17456          angular.module('limitToExample', [])
17457            .controller('ExampleController', ['$scope', function($scope) {
17458              $scope.numbers = [1,2,3,4,5,6,7,8,9];
17459              $scope.letters = "abcdefghi";
17460              $scope.longNumber = 2345432342;
17461              $scope.numLimit = 3;
17462              $scope.letterLimit = 3;
17463              $scope.longNumberLimit = 3;
17464            }]);
17465        </script>
17466        <div ng-controller="ExampleController">
17467          Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
17468          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
17469          Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
17470          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
17471          Limit {{longNumber}} to: <input type="number" step="1" ng-model="longNumberLimit">
17472          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
17473        </div>
17474      </file>
17475      <file name="protractor.js" type="protractor">
17476        var numLimitInput = element(by.model('numLimit'));
17477        var letterLimitInput = element(by.model('letterLimit'));
17478        var longNumberLimitInput = element(by.model('longNumberLimit'));
17479        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
17480        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
17481        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
17482
17483        it('should limit the number array to first three items', function() {
17484          expect(numLimitInput.getAttribute('value')).toBe('3');
17485          expect(letterLimitInput.getAttribute('value')).toBe('3');
17486          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
17487          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
17488          expect(limitedLetters.getText()).toEqual('Output letters: abc');
17489          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
17490        });
17491
17492        // There is a bug in safari and protractor that doesn't like the minus key
17493        // it('should update the output when -3 is entered', function() {
17494        //   numLimitInput.clear();
17495        //   numLimitInput.sendKeys('-3');
17496        //   letterLimitInput.clear();
17497        //   letterLimitInput.sendKeys('-3');
17498        //   longNumberLimitInput.clear();
17499        //   longNumberLimitInput.sendKeys('-3');
17500        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
17501        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
17502        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
17503        // });
17504
17505        it('should not exceed the maximum size of input array', function() {
17506          numLimitInput.clear();
17507          numLimitInput.sendKeys('100');
17508          letterLimitInput.clear();
17509          letterLimitInput.sendKeys('100');
17510          longNumberLimitInput.clear();
17511          longNumberLimitInput.sendKeys('100');
17512          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
17513          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
17514          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
17515        });
17516      </file>
17517    </example>
17518 */
17519 function limitToFilter() {
17520   return function(input, limit) {
17521     if (isNumber(input)) input = input.toString();
17522     if (!isArray(input) && !isString(input)) return input;
17523
17524     if (Math.abs(Number(limit)) === Infinity) {
17525       limit = Number(limit);
17526     } else {
17527       limit = int(limit);
17528     }
17529
17530     //NaN check on limit
17531     if (limit) {
17532       return limit > 0 ? input.slice(0, limit) : input.slice(limit);
17533     } else {
17534       return isString(input) ? "" : [];
17535     }
17536   };
17537 }
17538
17539 /**
17540  * @ngdoc filter
17541  * @name orderBy
17542  * @kind function
17543  *
17544  * @description
17545  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
17546  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
17547  * correctly, make sure they are actually being saved as numbers and not strings.
17548  *
17549  * @param {Array} array The array to sort.
17550  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
17551  *    used by the comparator to determine the order of elements.
17552  *
17553  *    Can be one of:
17554  *
17555  *    - `function`: Getter function. The result of this function will be sorted using the
17556  *      `<`, `=`, `>` operator.
17557  *    - `string`: An Angular expression. The result of this expression is used to compare elements
17558  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
17559  *      3 first characters of a property called `name`). The result of a constant expression
17560  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
17561  *      to sort object by the value of their `special name` property). An expression can be
17562  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
17563  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
17564  *      element itself is used to compare where sorting.
17565  *    - `Array`: An array of function or string predicates. The first predicate in the array
17566  *      is used for sorting, but when two items are equivalent, the next predicate is used.
17567  *
17568  *    If the predicate is missing or empty then it defaults to `'+'`.
17569  *
17570  * @param {boolean=} reverse Reverse the order of the array.
17571  * @returns {Array} Sorted copy of the source array.
17572  *
17573  *
17574  * @example
17575  * The example below demonstrates a simple ngRepeat, where the data is sorted
17576  * by age in descending order (predicate is set to `'-age'`).
17577  * `reverse` is not set, which means it defaults to `false`.
17578    <example module="orderByExample">
17579      <file name="index.html">
17580        <script>
17581          angular.module('orderByExample', [])
17582            .controller('ExampleController', ['$scope', function($scope) {
17583              $scope.friends =
17584                  [{name:'John', phone:'555-1212', age:10},
17585                   {name:'Mary', phone:'555-9876', age:19},
17586                   {name:'Mike', phone:'555-4321', age:21},
17587                   {name:'Adam', phone:'555-5678', age:35},
17588                   {name:'Julie', phone:'555-8765', age:29}];
17589            }]);
17590        </script>
17591        <div ng-controller="ExampleController">
17592          <table class="friend">
17593            <tr>
17594              <th>Name</th>
17595              <th>Phone Number</th>
17596              <th>Age</th>
17597            </tr>
17598            <tr ng-repeat="friend in friends | orderBy:'-age'">
17599              <td>{{friend.name}}</td>
17600              <td>{{friend.phone}}</td>
17601              <td>{{friend.age}}</td>
17602            </tr>
17603          </table>
17604        </div>
17605      </file>
17606    </example>
17607  *
17608  * The predicate and reverse parameters can be controlled dynamically through scope properties,
17609  * as shown in the next example.
17610  * @example
17611    <example module="orderByExample">
17612      <file name="index.html">
17613        <script>
17614          angular.module('orderByExample', [])
17615            .controller('ExampleController', ['$scope', function($scope) {
17616              $scope.friends =
17617                  [{name:'John', phone:'555-1212', age:10},
17618                   {name:'Mary', phone:'555-9876', age:19},
17619                   {name:'Mike', phone:'555-4321', age:21},
17620                   {name:'Adam', phone:'555-5678', age:35},
17621                   {name:'Julie', phone:'555-8765', age:29}];
17622              $scope.predicate = '-age';
17623            }]);
17624        </script>
17625        <div ng-controller="ExampleController">
17626          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
17627          <hr/>
17628          [ <a href="" ng-click="predicate=''">unsorted</a> ]
17629          <table class="friend">
17630            <tr>
17631              <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
17632                  (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
17633              <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
17634              <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
17635            </tr>
17636            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
17637              <td>{{friend.name}}</td>
17638              <td>{{friend.phone}}</td>
17639              <td>{{friend.age}}</td>
17640            </tr>
17641          </table>
17642        </div>
17643      </file>
17644    </example>
17645  *
17646  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
17647  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
17648  * desired parameters.
17649  *
17650  * Example:
17651  *
17652  * @example
17653   <example module="orderByExample">
17654     <file name="index.html">
17655       <div ng-controller="ExampleController">
17656         <table class="friend">
17657           <tr>
17658             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
17659               (<a href="" ng-click="order('-name',false)">^</a>)</th>
17660             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
17661             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
17662           </tr>
17663           <tr ng-repeat="friend in friends">
17664             <td>{{friend.name}}</td>
17665             <td>{{friend.phone}}</td>
17666             <td>{{friend.age}}</td>
17667           </tr>
17668         </table>
17669       </div>
17670     </file>
17671
17672     <file name="script.js">
17673       angular.module('orderByExample', [])
17674         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
17675           var orderBy = $filter('orderBy');
17676           $scope.friends = [
17677             { name: 'John',    phone: '555-1212',    age: 10 },
17678             { name: 'Mary',    phone: '555-9876',    age: 19 },
17679             { name: 'Mike',    phone: '555-4321',    age: 21 },
17680             { name: 'Adam',    phone: '555-5678',    age: 35 },
17681             { name: 'Julie',   phone: '555-8765',    age: 29 }
17682           ];
17683           $scope.order = function(predicate, reverse) {
17684             $scope.friends = orderBy($scope.friends, predicate, reverse);
17685           };
17686           $scope.order('-age',false);
17687         }]);
17688     </file>
17689 </example>
17690  */
17691 orderByFilter.$inject = ['$parse'];
17692 function orderByFilter($parse) {
17693   return function(array, sortPredicate, reverseOrder) {
17694     if (!(isArrayLike(array))) return array;
17695     sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
17696     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
17697     sortPredicate = sortPredicate.map(function(predicate) {
17698       var descending = false, get = predicate || identity;
17699       if (isString(predicate)) {
17700         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
17701           descending = predicate.charAt(0) == '-';
17702           predicate = predicate.substring(1);
17703         }
17704         if (predicate === '') {
17705           // Effectively no predicate was passed so we compare identity
17706           return reverseComparator(compare, descending);
17707         }
17708         get = $parse(predicate);
17709         if (get.constant) {
17710           var key = get();
17711           return reverseComparator(function(a, b) {
17712             return compare(a[key], b[key]);
17713           }, descending);
17714         }
17715       }
17716       return reverseComparator(function(a, b) {
17717         return compare(get(a),get(b));
17718       }, descending);
17719     });
17720     return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
17721
17722     function comparator(o1, o2) {
17723       for (var i = 0; i < sortPredicate.length; i++) {
17724         var comp = sortPredicate[i](o1, o2);
17725         if (comp !== 0) return comp;
17726       }
17727       return 0;
17728     }
17729     function reverseComparator(comp, descending) {
17730       return descending
17731           ? function(a, b) {return comp(b,a);}
17732           : comp;
17733     }
17734
17735     function isPrimitive(value) {
17736       switch (typeof value) {
17737         case 'number': /* falls through */
17738         case 'boolean': /* falls through */
17739         case 'string':
17740           return true;
17741         default:
17742           return false;
17743       }
17744     }
17745
17746     function objectToString(value) {
17747       if (value === null) return 'null';
17748       if (typeof value.valueOf === 'function') {
17749         value = value.valueOf();
17750         if (isPrimitive(value)) return value;
17751       }
17752       if (typeof value.toString === 'function') {
17753         value = value.toString();
17754         if (isPrimitive(value)) return value;
17755       }
17756       return '';
17757     }
17758
17759     function compare(v1, v2) {
17760       var t1 = typeof v1;
17761       var t2 = typeof v2;
17762       if (t1 === t2 && t1 === "object") {
17763         v1 = objectToString(v1);
17764         v2 = objectToString(v2);
17765       }
17766       if (t1 === t2) {
17767         if (t1 === "string") {
17768            v1 = v1.toLowerCase();
17769            v2 = v2.toLowerCase();
17770         }
17771         if (v1 === v2) return 0;
17772         return v1 < v2 ? -1 : 1;
17773       } else {
17774         return t1 < t2 ? -1 : 1;
17775       }
17776     }
17777   };
17778 }
17779
17780 function ngDirective(directive) {
17781   if (isFunction(directive)) {
17782     directive = {
17783       link: directive
17784     };
17785   }
17786   directive.restrict = directive.restrict || 'AC';
17787   return valueFn(directive);
17788 }
17789
17790 /**
17791  * @ngdoc directive
17792  * @name a
17793  * @restrict E
17794  *
17795  * @description
17796  * Modifies the default behavior of the html A tag so that the default action is prevented when
17797  * the href attribute is empty.
17798  *
17799  * This change permits the easy creation of action links with the `ngClick` directive
17800  * without changing the location or causing page reloads, e.g.:
17801  * `<a href="" ng-click="list.addItem()">Add Item</a>`
17802  */
17803 var htmlAnchorDirective = valueFn({
17804   restrict: 'E',
17805   compile: function(element, attr) {
17806     if (!attr.href && !attr.xlinkHref && !attr.name) {
17807       return function(scope, element) {
17808         // If the linked element is not an anchor tag anymore, do nothing
17809         if (element[0].nodeName.toLowerCase() !== 'a') return;
17810
17811         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
17812         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
17813                    'xlink:href' : 'href';
17814         element.on('click', function(event) {
17815           // if we have no href url, then don't navigate anywhere.
17816           if (!element.attr(href)) {
17817             event.preventDefault();
17818           }
17819         });
17820       };
17821     }
17822   }
17823 });
17824
17825 /**
17826  * @ngdoc directive
17827  * @name ngHref
17828  * @restrict A
17829  * @priority 99
17830  *
17831  * @description
17832  * Using Angular markup like `{{hash}}` in an href attribute will
17833  * make the link go to the wrong URL if the user clicks it before
17834  * Angular has a chance to replace the `{{hash}}` markup with its
17835  * value. Until Angular replaces the markup the link will be broken
17836  * and will most likely return a 404 error. The `ngHref` directive
17837  * solves this problem.
17838  *
17839  * The wrong way to write it:
17840  * ```html
17841  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17842  * ```
17843  *
17844  * The correct way to write it:
17845  * ```html
17846  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17847  * ```
17848  *
17849  * @element A
17850  * @param {template} ngHref any string which can contain `{{}}` markup.
17851  *
17852  * @example
17853  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
17854  * in links and their different behaviors:
17855     <example>
17856       <file name="index.html">
17857         <input ng-model="value" /><br />
17858         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
17859         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
17860         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
17861         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
17862         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
17863         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
17864       </file>
17865       <file name="protractor.js" type="protractor">
17866         it('should execute ng-click but not reload when href without value', function() {
17867           element(by.id('link-1')).click();
17868           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
17869           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
17870         });
17871
17872         it('should execute ng-click but not reload when href empty string', function() {
17873           element(by.id('link-2')).click();
17874           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
17875           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
17876         });
17877
17878         it('should execute ng-click and change url when ng-href specified', function() {
17879           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
17880
17881           element(by.id('link-3')).click();
17882
17883           // At this point, we navigate away from an Angular page, so we need
17884           // to use browser.driver to get the base webdriver.
17885
17886           browser.wait(function() {
17887             return browser.driver.getCurrentUrl().then(function(url) {
17888               return url.match(/\/123$/);
17889             });
17890           }, 5000, 'page should navigate to /123');
17891         });
17892
17893         xit('should execute ng-click but not reload when href empty string and name specified', function() {
17894           element(by.id('link-4')).click();
17895           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
17896           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
17897         });
17898
17899         it('should execute ng-click but not reload when no href but name specified', function() {
17900           element(by.id('link-5')).click();
17901           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
17902           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
17903         });
17904
17905         it('should only change url when only ng-href', function() {
17906           element(by.model('value')).clear();
17907           element(by.model('value')).sendKeys('6');
17908           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
17909
17910           element(by.id('link-6')).click();
17911
17912           // At this point, we navigate away from an Angular page, so we need
17913           // to use browser.driver to get the base webdriver.
17914           browser.wait(function() {
17915             return browser.driver.getCurrentUrl().then(function(url) {
17916               return url.match(/\/6$/);
17917             });
17918           }, 5000, 'page should navigate to /6');
17919         });
17920       </file>
17921     </example>
17922  */
17923
17924 /**
17925  * @ngdoc directive
17926  * @name ngSrc
17927  * @restrict A
17928  * @priority 99
17929  *
17930  * @description
17931  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
17932  * work right: The browser will fetch from the URL with the literal
17933  * text `{{hash}}` until Angular replaces the expression inside
17934  * `{{hash}}`. The `ngSrc` directive solves this problem.
17935  *
17936  * The buggy way to write it:
17937  * ```html
17938  * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
17939  * ```
17940  *
17941  * The correct way to write it:
17942  * ```html
17943  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
17944  * ```
17945  *
17946  * @element IMG
17947  * @param {template} ngSrc any string which can contain `{{}}` markup.
17948  */
17949
17950 /**
17951  * @ngdoc directive
17952  * @name ngSrcset
17953  * @restrict A
17954  * @priority 99
17955  *
17956  * @description
17957  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
17958  * work right: The browser will fetch from the URL with the literal
17959  * text `{{hash}}` until Angular replaces the expression inside
17960  * `{{hash}}`. The `ngSrcset` directive solves this problem.
17961  *
17962  * The buggy way to write it:
17963  * ```html
17964  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
17965  * ```
17966  *
17967  * The correct way to write it:
17968  * ```html
17969  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
17970  * ```
17971  *
17972  * @element IMG
17973  * @param {template} ngSrcset any string which can contain `{{}}` markup.
17974  */
17975
17976 /**
17977  * @ngdoc directive
17978  * @name ngDisabled
17979  * @restrict A
17980  * @priority 100
17981  *
17982  * @description
17983  *
17984  * This directive sets the `disabled` attribute on the element if the
17985  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
17986  *
17987  * A special directive is necessary because we cannot use interpolation inside the `disabled`
17988  * attribute.  The following example would make the button enabled on Chrome/Firefox
17989  * but not on older IEs:
17990  *
17991  * ```html
17992  * <!-- See below for an example of ng-disabled being used correctly -->
17993  * <div ng-init="isDisabled = false">
17994  *  <button disabled="{{isDisabled}}">Disabled</button>
17995  * </div>
17996  * ```
17997  *
17998  * This is because the HTML specification does not require browsers to preserve the values of
17999  * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
18000  * If we put an Angular interpolation expression into such an attribute then the
18001  * binding information would be lost when the browser removes the attribute.
18002  *
18003  * @example
18004     <example>
18005       <file name="index.html">
18006         Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
18007         <button ng-model="button" ng-disabled="checked">Button</button>
18008       </file>
18009       <file name="protractor.js" type="protractor">
18010         it('should toggle button', function() {
18011           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
18012           element(by.model('checked')).click();
18013           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
18014         });
18015       </file>
18016     </example>
18017  *
18018  * @element INPUT
18019  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
18020  *     then the `disabled` attribute will be set on the element
18021  */
18022
18023
18024 /**
18025  * @ngdoc directive
18026  * @name ngChecked
18027  * @restrict A
18028  * @priority 100
18029  *
18030  * @description
18031  * The HTML specification does not require browsers to preserve the values of boolean attributes
18032  * such as checked. (Their presence means true and their absence means false.)
18033  * If we put an Angular interpolation expression into such an attribute then the
18034  * binding information would be lost when the browser removes the attribute.
18035  * The `ngChecked` directive solves this problem for the `checked` attribute.
18036  * This complementary directive is not removed by the browser and so provides
18037  * a permanent reliable place to store the binding information.
18038  * @example
18039     <example>
18040       <file name="index.html">
18041         Check me to check both: <input type="checkbox" ng-model="master"><br/>
18042         <input id="checkSlave" type="checkbox" ng-checked="master">
18043       </file>
18044       <file name="protractor.js" type="protractor">
18045         it('should check both checkBoxes', function() {
18046           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
18047           element(by.model('master')).click();
18048           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
18049         });
18050       </file>
18051     </example>
18052  *
18053  * @element INPUT
18054  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
18055  *     then special attribute "checked" will be set on the element
18056  */
18057
18058
18059 /**
18060  * @ngdoc directive
18061  * @name ngReadonly
18062  * @restrict A
18063  * @priority 100
18064  *
18065  * @description
18066  * The HTML specification does not require browsers to preserve the values of boolean attributes
18067  * such as readonly. (Their presence means true and their absence means false.)
18068  * If we put an Angular interpolation expression into such an attribute then the
18069  * binding information would be lost when the browser removes the attribute.
18070  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
18071  * This complementary directive is not removed by the browser and so provides
18072  * a permanent reliable place to store the binding information.
18073  * @example
18074     <example>
18075       <file name="index.html">
18076         Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
18077         <input type="text" ng-readonly="checked" value="I'm Angular"/>
18078       </file>
18079       <file name="protractor.js" type="protractor">
18080         it('should toggle readonly attr', function() {
18081           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
18082           element(by.model('checked')).click();
18083           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
18084         });
18085       </file>
18086     </example>
18087  *
18088  * @element INPUT
18089  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
18090  *     then special attribute "readonly" will be set on the element
18091  */
18092
18093
18094 /**
18095  * @ngdoc directive
18096  * @name ngSelected
18097  * @restrict A
18098  * @priority 100
18099  *
18100  * @description
18101  * The HTML specification does not require browsers to preserve the values of boolean attributes
18102  * such as selected. (Their presence means true and their absence means false.)
18103  * If we put an Angular interpolation expression into such an attribute then the
18104  * binding information would be lost when the browser removes the attribute.
18105  * The `ngSelected` directive solves this problem for the `selected` attribute.
18106  * This complementary directive is not removed by the browser and so provides
18107  * a permanent reliable place to store the binding information.
18108  *
18109  * @example
18110     <example>
18111       <file name="index.html">
18112         Check me to select: <input type="checkbox" ng-model="selected"><br/>
18113         <select>
18114           <option>Hello!</option>
18115           <option id="greet" ng-selected="selected">Greetings!</option>
18116         </select>
18117       </file>
18118       <file name="protractor.js" type="protractor">
18119         it('should select Greetings!', function() {
18120           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
18121           element(by.model('selected')).click();
18122           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
18123         });
18124       </file>
18125     </example>
18126  *
18127  * @element OPTION
18128  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
18129  *     then special attribute "selected" will be set on the element
18130  */
18131
18132 /**
18133  * @ngdoc directive
18134  * @name ngOpen
18135  * @restrict A
18136  * @priority 100
18137  *
18138  * @description
18139  * The HTML specification does not require browsers to preserve the values of boolean attributes
18140  * such as open. (Their presence means true and their absence means false.)
18141  * If we put an Angular interpolation expression into such an attribute then the
18142  * binding information would be lost when the browser removes the attribute.
18143  * The `ngOpen` directive solves this problem for the `open` attribute.
18144  * This complementary directive is not removed by the browser and so provides
18145  * a permanent reliable place to store the binding information.
18146  * @example
18147      <example>
18148        <file name="index.html">
18149          Check me check multiple: <input type="checkbox" ng-model="open"><br/>
18150          <details id="details" ng-open="open">
18151             <summary>Show/Hide me</summary>
18152          </details>
18153        </file>
18154        <file name="protractor.js" type="protractor">
18155          it('should toggle open', function() {
18156            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
18157            element(by.model('open')).click();
18158            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
18159          });
18160        </file>
18161      </example>
18162  *
18163  * @element DETAILS
18164  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
18165  *     then special attribute "open" will be set on the element
18166  */
18167
18168 var ngAttributeAliasDirectives = {};
18169
18170
18171 // boolean attrs are evaluated
18172 forEach(BOOLEAN_ATTR, function(propName, attrName) {
18173   // binding to multiple is not supported
18174   if (propName == "multiple") return;
18175
18176   var normalized = directiveNormalize('ng-' + attrName);
18177   ngAttributeAliasDirectives[normalized] = function() {
18178     return {
18179       restrict: 'A',
18180       priority: 100,
18181       link: function(scope, element, attr) {
18182         scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
18183           attr.$set(attrName, !!value);
18184         });
18185       }
18186     };
18187   };
18188 });
18189
18190 // aliased input attrs are evaluated
18191 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
18192   ngAttributeAliasDirectives[ngAttr] = function() {
18193     return {
18194       priority: 100,
18195       link: function(scope, element, attr) {
18196         //special case ngPattern when a literal regular expression value
18197         //is used as the expression (this way we don't have to watch anything).
18198         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
18199           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
18200           if (match) {
18201             attr.$set("ngPattern", new RegExp(match[1], match[2]));
18202             return;
18203           }
18204         }
18205
18206         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
18207           attr.$set(ngAttr, value);
18208         });
18209       }
18210     };
18211   };
18212 });
18213
18214 // ng-src, ng-srcset, ng-href are interpolated
18215 forEach(['src', 'srcset', 'href'], function(attrName) {
18216   var normalized = directiveNormalize('ng-' + attrName);
18217   ngAttributeAliasDirectives[normalized] = function() {
18218     return {
18219       priority: 99, // it needs to run after the attributes are interpolated
18220       link: function(scope, element, attr) {
18221         var propName = attrName,
18222             name = attrName;
18223
18224         if (attrName === 'href' &&
18225             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
18226           name = 'xlinkHref';
18227           attr.$attr[name] = 'xlink:href';
18228           propName = null;
18229         }
18230
18231         attr.$observe(normalized, function(value) {
18232           if (!value) {
18233             if (attrName === 'href') {
18234               attr.$set(name, null);
18235             }
18236             return;
18237           }
18238
18239           attr.$set(name, value);
18240
18241           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
18242           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
18243           // to set the property as well to achieve the desired effect.
18244           // we use attr[attrName] value since $set can sanitize the url.
18245           if (msie && propName) element.prop(propName, attr[name]);
18246         });
18247       }
18248     };
18249   };
18250 });
18251
18252 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
18253  */
18254 var nullFormCtrl = {
18255   $addControl: noop,
18256   $$renameControl: nullFormRenameControl,
18257   $removeControl: noop,
18258   $setValidity: noop,
18259   $setDirty: noop,
18260   $setPristine: noop,
18261   $setSubmitted: noop
18262 },
18263 SUBMITTED_CLASS = 'ng-submitted';
18264
18265 function nullFormRenameControl(control, name) {
18266   control.$name = name;
18267 }
18268
18269 /**
18270  * @ngdoc type
18271  * @name form.FormController
18272  *
18273  * @property {boolean} $pristine True if user has not interacted with the form yet.
18274  * @property {boolean} $dirty True if user has already interacted with the form.
18275  * @property {boolean} $valid True if all of the containing forms and controls are valid.
18276  * @property {boolean} $invalid True if at least one containing control or form is invalid.
18277  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
18278  *
18279  * @property {Object} $error Is an object hash, containing references to controls or
18280  *  forms with failing validators, where:
18281  *
18282  *  - keys are validation tokens (error names),
18283  *  - values are arrays of controls or forms that have a failing validator for given error name.
18284  *
18285  *  Built-in validation tokens:
18286  *
18287  *  - `email`
18288  *  - `max`
18289  *  - `maxlength`
18290  *  - `min`
18291  *  - `minlength`
18292  *  - `number`
18293  *  - `pattern`
18294  *  - `required`
18295  *  - `url`
18296  *  - `date`
18297  *  - `datetimelocal`
18298  *  - `time`
18299  *  - `week`
18300  *  - `month`
18301  *
18302  * @description
18303  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
18304  * such as being valid/invalid or dirty/pristine.
18305  *
18306  * Each {@link ng.directive:form form} directive creates an instance
18307  * of `FormController`.
18308  *
18309  */
18310 //asks for $scope to fool the BC controller module
18311 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
18312 function FormController(element, attrs, $scope, $animate, $interpolate) {
18313   var form = this,
18314       controls = [];
18315
18316   var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
18317
18318   // init state
18319   form.$error = {};
18320   form.$$success = {};
18321   form.$pending = undefined;
18322   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
18323   form.$dirty = false;
18324   form.$pristine = true;
18325   form.$valid = true;
18326   form.$invalid = false;
18327   form.$submitted = false;
18328
18329   parentForm.$addControl(form);
18330
18331   /**
18332    * @ngdoc method
18333    * @name form.FormController#$rollbackViewValue
18334    *
18335    * @description
18336    * Rollback all form controls pending updates to the `$modelValue`.
18337    *
18338    * Updates may be pending by a debounced event or because the input is waiting for a some future
18339    * event defined in `ng-model-options`. This method is typically needed by the reset button of
18340    * a form that uses `ng-model-options` to pend updates.
18341    */
18342   form.$rollbackViewValue = function() {
18343     forEach(controls, function(control) {
18344       control.$rollbackViewValue();
18345     });
18346   };
18347
18348   /**
18349    * @ngdoc method
18350    * @name form.FormController#$commitViewValue
18351    *
18352    * @description
18353    * Commit all form controls pending updates to the `$modelValue`.
18354    *
18355    * Updates may be pending by a debounced event or because the input is waiting for a some future
18356    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
18357    * usually handles calling this in response to input events.
18358    */
18359   form.$commitViewValue = function() {
18360     forEach(controls, function(control) {
18361       control.$commitViewValue();
18362     });
18363   };
18364
18365   /**
18366    * @ngdoc method
18367    * @name form.FormController#$addControl
18368    *
18369    * @description
18370    * Register a control with the form.
18371    *
18372    * Input elements using ngModelController do this automatically when they are linked.
18373    */
18374   form.$addControl = function(control) {
18375     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
18376     // and not added to the scope.  Now we throw an error.
18377     assertNotHasOwnProperty(control.$name, 'input');
18378     controls.push(control);
18379
18380     if (control.$name) {
18381       form[control.$name] = control;
18382     }
18383   };
18384
18385   // Private API: rename a form control
18386   form.$$renameControl = function(control, newName) {
18387     var oldName = control.$name;
18388
18389     if (form[oldName] === control) {
18390       delete form[oldName];
18391     }
18392     form[newName] = control;
18393     control.$name = newName;
18394   };
18395
18396   /**
18397    * @ngdoc method
18398    * @name form.FormController#$removeControl
18399    *
18400    * @description
18401    * Deregister a control from the form.
18402    *
18403    * Input elements using ngModelController do this automatically when they are destroyed.
18404    */
18405   form.$removeControl = function(control) {
18406     if (control.$name && form[control.$name] === control) {
18407       delete form[control.$name];
18408     }
18409     forEach(form.$pending, function(value, name) {
18410       form.$setValidity(name, null, control);
18411     });
18412     forEach(form.$error, function(value, name) {
18413       form.$setValidity(name, null, control);
18414     });
18415     forEach(form.$$success, function(value, name) {
18416       form.$setValidity(name, null, control);
18417     });
18418
18419     arrayRemove(controls, control);
18420   };
18421
18422
18423   /**
18424    * @ngdoc method
18425    * @name form.FormController#$setValidity
18426    *
18427    * @description
18428    * Sets the validity of a form control.
18429    *
18430    * This method will also propagate to parent forms.
18431    */
18432   addSetValidityMethod({
18433     ctrl: this,
18434     $element: element,
18435     set: function(object, property, controller) {
18436       var list = object[property];
18437       if (!list) {
18438         object[property] = [controller];
18439       } else {
18440         var index = list.indexOf(controller);
18441         if (index === -1) {
18442           list.push(controller);
18443         }
18444       }
18445     },
18446     unset: function(object, property, controller) {
18447       var list = object[property];
18448       if (!list) {
18449         return;
18450       }
18451       arrayRemove(list, controller);
18452       if (list.length === 0) {
18453         delete object[property];
18454       }
18455     },
18456     parentForm: parentForm,
18457     $animate: $animate
18458   });
18459
18460   /**
18461    * @ngdoc method
18462    * @name form.FormController#$setDirty
18463    *
18464    * @description
18465    * Sets the form to a dirty state.
18466    *
18467    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
18468    * state (ng-dirty class). This method will also propagate to parent forms.
18469    */
18470   form.$setDirty = function() {
18471     $animate.removeClass(element, PRISTINE_CLASS);
18472     $animate.addClass(element, DIRTY_CLASS);
18473     form.$dirty = true;
18474     form.$pristine = false;
18475     parentForm.$setDirty();
18476   };
18477
18478   /**
18479    * @ngdoc method
18480    * @name form.FormController#$setPristine
18481    *
18482    * @description
18483    * Sets the form to its pristine state.
18484    *
18485    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
18486    * state (ng-pristine class). This method will also propagate to all the controls contained
18487    * in this form.
18488    *
18489    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
18490    * saving or resetting it.
18491    */
18492   form.$setPristine = function() {
18493     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
18494     form.$dirty = false;
18495     form.$pristine = true;
18496     form.$submitted = false;
18497     forEach(controls, function(control) {
18498       control.$setPristine();
18499     });
18500   };
18501
18502   /**
18503    * @ngdoc method
18504    * @name form.FormController#$setUntouched
18505    *
18506    * @description
18507    * Sets the form to its untouched state.
18508    *
18509    * This method can be called to remove the 'ng-touched' class and set the form controls to their
18510    * untouched state (ng-untouched class).
18511    *
18512    * Setting a form controls back to their untouched state is often useful when setting the form
18513    * back to its pristine state.
18514    */
18515   form.$setUntouched = function() {
18516     forEach(controls, function(control) {
18517       control.$setUntouched();
18518     });
18519   };
18520
18521   /**
18522    * @ngdoc method
18523    * @name form.FormController#$setSubmitted
18524    *
18525    * @description
18526    * Sets the form to its submitted state.
18527    */
18528   form.$setSubmitted = function() {
18529     $animate.addClass(element, SUBMITTED_CLASS);
18530     form.$submitted = true;
18531     parentForm.$setSubmitted();
18532   };
18533 }
18534
18535 /**
18536  * @ngdoc directive
18537  * @name ngForm
18538  * @restrict EAC
18539  *
18540  * @description
18541  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
18542  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
18543  * sub-group of controls needs to be determined.
18544  *
18545  * Note: the purpose of `ngForm` is to group controls,
18546  * but not to be a replacement for the `<form>` tag with all of its capabilities
18547  * (e.g. posting to the server, ...).
18548  *
18549  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
18550  *                       related scope, under this name.
18551  *
18552  */
18553
18554  /**
18555  * @ngdoc directive
18556  * @name form
18557  * @restrict E
18558  *
18559  * @description
18560  * Directive that instantiates
18561  * {@link form.FormController FormController}.
18562  *
18563  * If the `name` attribute is specified, the form controller is published onto the current scope under
18564  * this name.
18565  *
18566  * # Alias: {@link ng.directive:ngForm `ngForm`}
18567  *
18568  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
18569  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
18570  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
18571  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
18572  * using Angular validation directives in forms that are dynamically generated using the
18573  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
18574  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
18575  * `ngForm` directive and nest these in an outer `form` element.
18576  *
18577  *
18578  * # CSS classes
18579  *  - `ng-valid` is set if the form is valid.
18580  *  - `ng-invalid` is set if the form is invalid.
18581  *  - `ng-pristine` is set if the form is pristine.
18582  *  - `ng-dirty` is set if the form is dirty.
18583  *  - `ng-submitted` is set if the form was submitted.
18584  *
18585  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
18586  *
18587  *
18588  * # Submitting a form and preventing the default action
18589  *
18590  * Since the role of forms in client-side Angular applications is different than in classical
18591  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
18592  * page reload that sends the data to the server. Instead some javascript logic should be triggered
18593  * to handle the form submission in an application-specific way.
18594  *
18595  * For this reason, Angular prevents the default action (form submission to the server) unless the
18596  * `<form>` element has an `action` attribute specified.
18597  *
18598  * You can use one of the following two ways to specify what javascript method should be called when
18599  * a form is submitted:
18600  *
18601  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
18602  * - {@link ng.directive:ngClick ngClick} directive on the first
18603   *  button or input field of type submit (input[type=submit])
18604  *
18605  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
18606  * or {@link ng.directive:ngClick ngClick} directives.
18607  * This is because of the following form submission rules in the HTML specification:
18608  *
18609  * - If a form has only one input field then hitting enter in this field triggers form submit
18610  * (`ngSubmit`)
18611  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
18612  * doesn't trigger submit
18613  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
18614  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
18615  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
18616  *
18617  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
18618  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
18619  * to have access to the updated model.
18620  *
18621  * ## Animation Hooks
18622  *
18623  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
18624  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
18625  * other validations that are performed within the form. Animations in ngForm are similar to how
18626  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
18627  * as JS animations.
18628  *
18629  * The following example shows a simple way to utilize CSS transitions to style a form element
18630  * that has been rendered as invalid after it has been validated:
18631  *
18632  * <pre>
18633  * //be sure to include ngAnimate as a module to hook into more
18634  * //advanced animations
18635  * .my-form {
18636  *   transition:0.5s linear all;
18637  *   background: white;
18638  * }
18639  * .my-form.ng-invalid {
18640  *   background: red;
18641  *   color:white;
18642  * }
18643  * </pre>
18644  *
18645  * @example
18646     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
18647       <file name="index.html">
18648        <script>
18649          angular.module('formExample', [])
18650            .controller('FormController', ['$scope', function($scope) {
18651              $scope.userType = 'guest';
18652            }]);
18653        </script>
18654        <style>
18655         .my-form {
18656           -webkit-transition:all linear 0.5s;
18657           transition:all linear 0.5s;
18658           background: transparent;
18659         }
18660         .my-form.ng-invalid {
18661           background: red;
18662         }
18663        </style>
18664        <form name="myForm" ng-controller="FormController" class="my-form">
18665          userType: <input name="input" ng-model="userType" required>
18666          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
18667          <tt>userType = {{userType}}</tt><br>
18668          <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
18669          <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
18670          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
18671          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
18672         </form>
18673       </file>
18674       <file name="protractor.js" type="protractor">
18675         it('should initialize to model', function() {
18676           var userType = element(by.binding('userType'));
18677           var valid = element(by.binding('myForm.input.$valid'));
18678
18679           expect(userType.getText()).toContain('guest');
18680           expect(valid.getText()).toContain('true');
18681         });
18682
18683         it('should be invalid if empty', function() {
18684           var userType = element(by.binding('userType'));
18685           var valid = element(by.binding('myForm.input.$valid'));
18686           var userInput = element(by.model('userType'));
18687
18688           userInput.clear();
18689           userInput.sendKeys('');
18690
18691           expect(userType.getText()).toEqual('userType =');
18692           expect(valid.getText()).toContain('false');
18693         });
18694       </file>
18695     </example>
18696  *
18697  * @param {string=} name Name of the form. If specified, the form controller will be published into
18698  *                       related scope, under this name.
18699  */
18700 var formDirectiveFactory = function(isNgForm) {
18701   return ['$timeout', function($timeout) {
18702     var formDirective = {
18703       name: 'form',
18704       restrict: isNgForm ? 'EAC' : 'E',
18705       controller: FormController,
18706       compile: function ngFormCompile(formElement, attr) {
18707         // Setup initial state of the control
18708         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
18709
18710         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
18711
18712         return {
18713           pre: function ngFormPreLink(scope, formElement, attr, controller) {
18714             // if `action` attr is not present on the form, prevent the default action (submission)
18715             if (!('action' in attr)) {
18716               // we can't use jq events because if a form is destroyed during submission the default
18717               // action is not prevented. see #1238
18718               //
18719               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
18720               // page reload if the form was destroyed by submission of the form via a click handler
18721               // on a button in the form. Looks like an IE9 specific bug.
18722               var handleFormSubmission = function(event) {
18723                 scope.$apply(function() {
18724                   controller.$commitViewValue();
18725                   controller.$setSubmitted();
18726                 });
18727
18728                 event.preventDefault();
18729               };
18730
18731               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18732
18733               // unregister the preventDefault listener so that we don't not leak memory but in a
18734               // way that will achieve the prevention of the default action.
18735               formElement.on('$destroy', function() {
18736                 $timeout(function() {
18737                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18738                 }, 0, false);
18739               });
18740             }
18741
18742             var parentFormCtrl = controller.$$parentForm;
18743
18744             if (nameAttr) {
18745               setter(scope, null, controller.$name, controller, controller.$name);
18746               attr.$observe(nameAttr, function(newValue) {
18747                 if (controller.$name === newValue) return;
18748                 setter(scope, null, controller.$name, undefined, controller.$name);
18749                 parentFormCtrl.$$renameControl(controller, newValue);
18750                 setter(scope, null, controller.$name, controller, controller.$name);
18751               });
18752             }
18753             formElement.on('$destroy', function() {
18754               parentFormCtrl.$removeControl(controller);
18755               if (nameAttr) {
18756                 setter(scope, null, attr[nameAttr], undefined, controller.$name);
18757               }
18758               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
18759             });
18760           }
18761         };
18762       }
18763     };
18764
18765     return formDirective;
18766   }];
18767 };
18768
18769 var formDirective = formDirectiveFactory();
18770 var ngFormDirective = formDirectiveFactory(true);
18771
18772 /* global VALID_CLASS: false,
18773   INVALID_CLASS: false,
18774   PRISTINE_CLASS: false,
18775   DIRTY_CLASS: false,
18776   UNTOUCHED_CLASS: false,
18777   TOUCHED_CLASS: false,
18778   $ngModelMinErr: false,
18779 */
18780
18781 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
18782 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)/;
18783 var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
18784 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;
18785 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
18786 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
18787 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18788 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
18789 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
18790 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18791
18792 var inputType = {
18793
18794   /**
18795    * @ngdoc input
18796    * @name input[text]
18797    *
18798    * @description
18799    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
18800    *
18801    *
18802    * @param {string} ngModel Assignable angular expression to data-bind to.
18803    * @param {string=} name Property name of the form under which the control is published.
18804    * @param {string=} required Adds `required` validation error key if the value is not entered.
18805    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18806    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18807    *    `required` when you want to data-bind to the `required` attribute.
18808    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
18809    *    minlength.
18810    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
18811    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
18812    *    any length.
18813    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
18814    *    that contains the regular expression body that will be converted to a regular expression
18815    *    as in the ngPattern directive.
18816    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
18817    *    a RegExp found by evaluating the Angular expression given in the attribute value.
18818    *    If the expression evaluates to a RegExp object then this is used directly.
18819    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
18820    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
18821    * @param {string=} ngChange Angular expression to be executed when input changes due to user
18822    *    interaction with the input element.
18823    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
18824    *    This parameter is ignored for input[type=password] controls, which will never trim the
18825    *    input.
18826    *
18827    * @example
18828       <example name="text-input-directive" module="textInputExample">
18829         <file name="index.html">
18830          <script>
18831            angular.module('textInputExample', [])
18832              .controller('ExampleController', ['$scope', function($scope) {
18833                $scope.example = {
18834                  text: 'guest',
18835                  word: /^\s*\w*\s*$/
18836                };
18837              }]);
18838          </script>
18839          <form name="myForm" ng-controller="ExampleController">
18840            Single word: <input type="text" name="input" ng-model="example.text"
18841                                ng-pattern="example.word" required ng-trim="false">
18842            <span class="error" ng-show="myForm.input.$error.required">
18843              Required!</span>
18844            <span class="error" ng-show="myForm.input.$error.pattern">
18845              Single word only!</span>
18846
18847            <tt>text = {{example.text}}</tt><br/>
18848            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18849            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18850            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18851            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18852           </form>
18853         </file>
18854         <file name="protractor.js" type="protractor">
18855           var text = element(by.binding('example.text'));
18856           var valid = element(by.binding('myForm.input.$valid'));
18857           var input = element(by.model('example.text'));
18858
18859           it('should initialize to model', function() {
18860             expect(text.getText()).toContain('guest');
18861             expect(valid.getText()).toContain('true');
18862           });
18863
18864           it('should be invalid if empty', function() {
18865             input.clear();
18866             input.sendKeys('');
18867
18868             expect(text.getText()).toEqual('text =');
18869             expect(valid.getText()).toContain('false');
18870           });
18871
18872           it('should be invalid if multi word', function() {
18873             input.clear();
18874             input.sendKeys('hello world');
18875
18876             expect(valid.getText()).toContain('false');
18877           });
18878         </file>
18879       </example>
18880    */
18881   'text': textInputType,
18882
18883     /**
18884      * @ngdoc input
18885      * @name input[date]
18886      *
18887      * @description
18888      * Input with date validation and transformation. In browsers that do not yet support
18889      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
18890      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
18891      * modern browsers do not yet support this input type, it is important to provide cues to users on the
18892      * expected input format via a placeholder or label.
18893      *
18894      * The model must always be a Date object, otherwise Angular will throw an error.
18895      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
18896      *
18897      * The timezone to be used to read/write the `Date` instance in the model can be defined using
18898      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
18899      *
18900      * @param {string} ngModel Assignable angular expression to data-bind to.
18901      * @param {string=} name Property name of the form under which the control is published.
18902      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
18903      * valid ISO date string (yyyy-MM-dd).
18904      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
18905      * a valid ISO date string (yyyy-MM-dd).
18906      * @param {string=} required Sets `required` validation error key if the value is not entered.
18907      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18908      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18909      *    `required` when you want to data-bind to the `required` attribute.
18910      * @param {string=} ngChange Angular expression to be executed when input changes due to user
18911      *    interaction with the input element.
18912      *
18913      * @example
18914      <example name="date-input-directive" module="dateInputExample">
18915      <file name="index.html">
18916        <script>
18917           angular.module('dateInputExample', [])
18918             .controller('DateController', ['$scope', function($scope) {
18919               $scope.example = {
18920                 value: new Date(2013, 9, 22)
18921               };
18922             }]);
18923        </script>
18924        <form name="myForm" ng-controller="DateController as dateCtrl">
18925           Pick a date in 2013:
18926           <input type="date" id="exampleInput" name="input" ng-model="example.value"
18927               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
18928           <span class="error" ng-show="myForm.input.$error.required">
18929               Required!</span>
18930           <span class="error" ng-show="myForm.input.$error.date">
18931               Not a valid date!</span>
18932            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
18933            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18934            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18935            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18936            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18937        </form>
18938      </file>
18939      <file name="protractor.js" type="protractor">
18940         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
18941         var valid = element(by.binding('myForm.input.$valid'));
18942         var input = element(by.model('example.value'));
18943
18944         // currently protractor/webdriver does not support
18945         // sending keys to all known HTML5 input controls
18946         // for various browsers (see https://github.com/angular/protractor/issues/562).
18947         function setInput(val) {
18948           // set the value of the element and force validation.
18949           var scr = "var ipt = document.getElementById('exampleInput'); " +
18950           "ipt.value = '" + val + "';" +
18951           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
18952           browser.executeScript(scr);
18953         }
18954
18955         it('should initialize to model', function() {
18956           expect(value.getText()).toContain('2013-10-22');
18957           expect(valid.getText()).toContain('myForm.input.$valid = true');
18958         });
18959
18960         it('should be invalid if empty', function() {
18961           setInput('');
18962           expect(value.getText()).toEqual('value =');
18963           expect(valid.getText()).toContain('myForm.input.$valid = false');
18964         });
18965
18966         it('should be invalid if over max', function() {
18967           setInput('2015-01-01');
18968           expect(value.getText()).toContain('');
18969           expect(valid.getText()).toContain('myForm.input.$valid = false');
18970         });
18971      </file>
18972      </example>
18973      */
18974   'date': createDateInputType('date', DATE_REGEXP,
18975          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
18976          'yyyy-MM-dd'),
18977
18978    /**
18979     * @ngdoc input
18980     * @name input[datetime-local]
18981     *
18982     * @description
18983     * Input with datetime validation and transformation. In browsers that do not yet support
18984     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
18985     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
18986     *
18987     * The model must always be a Date object, otherwise Angular will throw an error.
18988     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
18989     *
18990     * The timezone to be used to read/write the `Date` instance in the model can be defined using
18991     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
18992     *
18993     * @param {string} ngModel Assignable angular expression to data-bind to.
18994     * @param {string=} name Property name of the form under which the control is published.
18995     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
18996     * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
18997     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
18998     * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
18999     * @param {string=} required Sets `required` validation error key if the value is not entered.
19000     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19001     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19002     *    `required` when you want to data-bind to the `required` attribute.
19003     * @param {string=} ngChange Angular expression to be executed when input changes due to user
19004     *    interaction with the input element.
19005     *
19006     * @example
19007     <example name="datetimelocal-input-directive" module="dateExample">
19008     <file name="index.html">
19009       <script>
19010         angular.module('dateExample', [])
19011           .controller('DateController', ['$scope', function($scope) {
19012             $scope.example = {
19013               value: new Date(2010, 11, 28, 14, 57)
19014             };
19015           }]);
19016       </script>
19017       <form name="myForm" ng-controller="DateController as dateCtrl">
19018         Pick a date between in 2013:
19019         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
19020             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
19021         <span class="error" ng-show="myForm.input.$error.required">
19022             Required!</span>
19023         <span class="error" ng-show="myForm.input.$error.datetimelocal">
19024             Not a valid date!</span>
19025         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
19026         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19027         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19028         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19029         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19030       </form>
19031     </file>
19032     <file name="protractor.js" type="protractor">
19033       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
19034       var valid = element(by.binding('myForm.input.$valid'));
19035       var input = element(by.model('example.value'));
19036
19037       // currently protractor/webdriver does not support
19038       // sending keys to all known HTML5 input controls
19039       // for various browsers (https://github.com/angular/protractor/issues/562).
19040       function setInput(val) {
19041         // set the value of the element and force validation.
19042         var scr = "var ipt = document.getElementById('exampleInput'); " +
19043         "ipt.value = '" + val + "';" +
19044         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19045         browser.executeScript(scr);
19046       }
19047
19048       it('should initialize to model', function() {
19049         expect(value.getText()).toContain('2010-12-28T14:57:00');
19050         expect(valid.getText()).toContain('myForm.input.$valid = true');
19051       });
19052
19053       it('should be invalid if empty', function() {
19054         setInput('');
19055         expect(value.getText()).toEqual('value =');
19056         expect(valid.getText()).toContain('myForm.input.$valid = false');
19057       });
19058
19059       it('should be invalid if over max', function() {
19060         setInput('2015-01-01T23:59:00');
19061         expect(value.getText()).toContain('');
19062         expect(valid.getText()).toContain('myForm.input.$valid = false');
19063       });
19064     </file>
19065     </example>
19066     */
19067   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
19068       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
19069       'yyyy-MM-ddTHH:mm:ss.sss'),
19070
19071   /**
19072    * @ngdoc input
19073    * @name input[time]
19074    *
19075    * @description
19076    * Input with time validation and transformation. In browsers that do not yet support
19077    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19078    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
19079    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
19080    *
19081    * The model must always be a Date object, otherwise Angular will throw an error.
19082    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19083    *
19084    * The timezone to be used to read/write the `Date` instance in the model can be defined using
19085    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19086    *
19087    * @param {string} ngModel Assignable angular expression to data-bind to.
19088    * @param {string=} name Property name of the form under which the control is published.
19089    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19090    * valid ISO time format (HH:mm:ss).
19091    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
19092    * valid ISO time format (HH:mm:ss).
19093    * @param {string=} required Sets `required` validation error key if the value is not entered.
19094    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19095    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19096    *    `required` when you want to data-bind to the `required` attribute.
19097    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19098    *    interaction with the input element.
19099    *
19100    * @example
19101    <example name="time-input-directive" module="timeExample">
19102    <file name="index.html">
19103      <script>
19104       angular.module('timeExample', [])
19105         .controller('DateController', ['$scope', function($scope) {
19106           $scope.example = {
19107             value: new Date(1970, 0, 1, 14, 57, 0)
19108           };
19109         }]);
19110      </script>
19111      <form name="myForm" ng-controller="DateController as dateCtrl">
19112         Pick a between 8am and 5pm:
19113         <input type="time" id="exampleInput" name="input" ng-model="example.value"
19114             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
19115         <span class="error" ng-show="myForm.input.$error.required">
19116             Required!</span>
19117         <span class="error" ng-show="myForm.input.$error.time">
19118             Not a valid date!</span>
19119         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
19120         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19121         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19122         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19123         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19124      </form>
19125    </file>
19126    <file name="protractor.js" type="protractor">
19127       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
19128       var valid = element(by.binding('myForm.input.$valid'));
19129       var input = element(by.model('example.value'));
19130
19131       // currently protractor/webdriver does not support
19132       // sending keys to all known HTML5 input controls
19133       // for various browsers (https://github.com/angular/protractor/issues/562).
19134       function setInput(val) {
19135         // set the value of the element and force validation.
19136         var scr = "var ipt = document.getElementById('exampleInput'); " +
19137         "ipt.value = '" + val + "';" +
19138         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19139         browser.executeScript(scr);
19140       }
19141
19142       it('should initialize to model', function() {
19143         expect(value.getText()).toContain('14:57:00');
19144         expect(valid.getText()).toContain('myForm.input.$valid = true');
19145       });
19146
19147       it('should be invalid if empty', function() {
19148         setInput('');
19149         expect(value.getText()).toEqual('value =');
19150         expect(valid.getText()).toContain('myForm.input.$valid = false');
19151       });
19152
19153       it('should be invalid if over max', function() {
19154         setInput('23:59:00');
19155         expect(value.getText()).toContain('');
19156         expect(valid.getText()).toContain('myForm.input.$valid = false');
19157       });
19158    </file>
19159    </example>
19160    */
19161   'time': createDateInputType('time', TIME_REGEXP,
19162       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
19163      'HH:mm:ss.sss'),
19164
19165    /**
19166     * @ngdoc input
19167     * @name input[week]
19168     *
19169     * @description
19170     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
19171     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19172     * week format (yyyy-W##), for example: `2013-W02`.
19173     *
19174     * The model must always be a Date object, otherwise Angular will throw an error.
19175     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19176     *
19177     * The timezone to be used to read/write the `Date` instance in the model can be defined using
19178     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19179     *
19180     * @param {string} ngModel Assignable angular expression to data-bind to.
19181     * @param {string=} name Property name of the form under which the control is published.
19182     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19183     * valid ISO week format (yyyy-W##).
19184     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
19185     * a valid ISO week format (yyyy-W##).
19186     * @param {string=} required Sets `required` validation error key if the value is not entered.
19187     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19188     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19189     *    `required` when you want to data-bind to the `required` attribute.
19190     * @param {string=} ngChange Angular expression to be executed when input changes due to user
19191     *    interaction with the input element.
19192     *
19193     * @example
19194     <example name="week-input-directive" module="weekExample">
19195     <file name="index.html">
19196       <script>
19197       angular.module('weekExample', [])
19198         .controller('DateController', ['$scope', function($scope) {
19199           $scope.example = {
19200             value: new Date(2013, 0, 3)
19201           };
19202         }]);
19203       </script>
19204       <form name="myForm" ng-controller="DateController as dateCtrl">
19205         Pick a date between in 2013:
19206         <input id="exampleInput" type="week" name="input" ng-model="example.value"
19207             placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
19208         <span class="error" ng-show="myForm.input.$error.required">
19209             Required!</span>
19210         <span class="error" ng-show="myForm.input.$error.week">
19211             Not a valid date!</span>
19212         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
19213         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19214         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19215         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19216         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19217       </form>
19218     </file>
19219     <file name="protractor.js" type="protractor">
19220       var value = element(by.binding('example.value | date: "yyyy-Www"'));
19221       var valid = element(by.binding('myForm.input.$valid'));
19222       var input = element(by.model('example.value'));
19223
19224       // currently protractor/webdriver does not support
19225       // sending keys to all known HTML5 input controls
19226       // for various browsers (https://github.com/angular/protractor/issues/562).
19227       function setInput(val) {
19228         // set the value of the element and force validation.
19229         var scr = "var ipt = document.getElementById('exampleInput'); " +
19230         "ipt.value = '" + val + "';" +
19231         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19232         browser.executeScript(scr);
19233       }
19234
19235       it('should initialize to model', function() {
19236         expect(value.getText()).toContain('2013-W01');
19237         expect(valid.getText()).toContain('myForm.input.$valid = true');
19238       });
19239
19240       it('should be invalid if empty', function() {
19241         setInput('');
19242         expect(value.getText()).toEqual('value =');
19243         expect(valid.getText()).toContain('myForm.input.$valid = false');
19244       });
19245
19246       it('should be invalid if over max', function() {
19247         setInput('2015-W01');
19248         expect(value.getText()).toContain('');
19249         expect(valid.getText()).toContain('myForm.input.$valid = false');
19250       });
19251     </file>
19252     </example>
19253     */
19254   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
19255
19256   /**
19257    * @ngdoc input
19258    * @name input[month]
19259    *
19260    * @description
19261    * Input with month validation and transformation. In browsers that do not yet support
19262    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19263    * month format (yyyy-MM), for example: `2009-01`.
19264    *
19265    * The model must always be a Date object, otherwise Angular will throw an error.
19266    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19267    * If the model is not set to the first of the month, the next view to model update will set it
19268    * to the first of the month.
19269    *
19270    * The timezone to be used to read/write the `Date` instance in the model can be defined using
19271    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19272    *
19273    * @param {string} ngModel Assignable angular expression to data-bind to.
19274    * @param {string=} name Property name of the form under which the control is published.
19275    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
19276    * a valid ISO month format (yyyy-MM).
19277    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
19278    * be a valid ISO month format (yyyy-MM).
19279    * @param {string=} required Sets `required` validation error key if the value is not entered.
19280    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19281    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19282    *    `required` when you want to data-bind to the `required` attribute.
19283    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19284    *    interaction with the input element.
19285    *
19286    * @example
19287    <example name="month-input-directive" module="monthExample">
19288    <file name="index.html">
19289      <script>
19290       angular.module('monthExample', [])
19291         .controller('DateController', ['$scope', function($scope) {
19292           $scope.example = {
19293             value: new Date(2013, 9, 1)
19294           };
19295         }]);
19296      </script>
19297      <form name="myForm" ng-controller="DateController as dateCtrl">
19298        Pick a month in 2013:
19299        <input id="exampleInput" type="month" name="input" ng-model="example.value"
19300           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
19301        <span class="error" ng-show="myForm.input.$error.required">
19302           Required!</span>
19303        <span class="error" ng-show="myForm.input.$error.month">
19304           Not a valid month!</span>
19305        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
19306        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19307        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19308        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19309        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19310      </form>
19311    </file>
19312    <file name="protractor.js" type="protractor">
19313       var value = element(by.binding('example.value | date: "yyyy-MM"'));
19314       var valid = element(by.binding('myForm.input.$valid'));
19315       var input = element(by.model('example.value'));
19316
19317       // currently protractor/webdriver does not support
19318       // sending keys to all known HTML5 input controls
19319       // for various browsers (https://github.com/angular/protractor/issues/562).
19320       function setInput(val) {
19321         // set the value of the element and force validation.
19322         var scr = "var ipt = document.getElementById('exampleInput'); " +
19323         "ipt.value = '" + val + "';" +
19324         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19325         browser.executeScript(scr);
19326       }
19327
19328       it('should initialize to model', function() {
19329         expect(value.getText()).toContain('2013-10');
19330         expect(valid.getText()).toContain('myForm.input.$valid = true');
19331       });
19332
19333       it('should be invalid if empty', function() {
19334         setInput('');
19335         expect(value.getText()).toEqual('value =');
19336         expect(valid.getText()).toContain('myForm.input.$valid = false');
19337       });
19338
19339       it('should be invalid if over max', function() {
19340         setInput('2015-01');
19341         expect(value.getText()).toContain('');
19342         expect(valid.getText()).toContain('myForm.input.$valid = false');
19343       });
19344    </file>
19345    </example>
19346    */
19347   'month': createDateInputType('month', MONTH_REGEXP,
19348      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
19349      'yyyy-MM'),
19350
19351   /**
19352    * @ngdoc input
19353    * @name input[number]
19354    *
19355    * @description
19356    * Text input with number validation and transformation. Sets the `number` validation
19357    * error if not a valid number.
19358    *
19359    * The model must always be a number, otherwise Angular will throw an error.
19360    *
19361    * @param {string} ngModel Assignable angular expression to data-bind to.
19362    * @param {string=} name Property name of the form under which the control is published.
19363    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
19364    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
19365    * @param {string=} required Sets `required` validation error key if the value is not entered.
19366    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19367    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19368    *    `required` when you want to data-bind to the `required` attribute.
19369    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19370    *    minlength.
19371    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19372    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19373    *    any length.
19374    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19375    *    that contains the regular expression body that will be converted to a regular expression
19376    *    as in the ngPattern directive.
19377    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19378    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19379    *    If the expression evaluates to a RegExp object then this is used directly.
19380    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19381    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19382    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19383    *    interaction with the input element.
19384    *
19385    * @example
19386       <example name="number-input-directive" module="numberExample">
19387         <file name="index.html">
19388          <script>
19389            angular.module('numberExample', [])
19390              .controller('ExampleController', ['$scope', function($scope) {
19391                $scope.example = {
19392                  value: 12
19393                };
19394              }]);
19395          </script>
19396          <form name="myForm" ng-controller="ExampleController">
19397            Number: <input type="number" name="input" ng-model="example.value"
19398                           min="0" max="99" required>
19399            <span class="error" ng-show="myForm.input.$error.required">
19400              Required!</span>
19401            <span class="error" ng-show="myForm.input.$error.number">
19402              Not valid number!</span>
19403            <tt>value = {{example.value}}</tt><br/>
19404            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19405            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19406            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19407            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19408           </form>
19409         </file>
19410         <file name="protractor.js" type="protractor">
19411           var value = element(by.binding('example.value'));
19412           var valid = element(by.binding('myForm.input.$valid'));
19413           var input = element(by.model('example.value'));
19414
19415           it('should initialize to model', function() {
19416             expect(value.getText()).toContain('12');
19417             expect(valid.getText()).toContain('true');
19418           });
19419
19420           it('should be invalid if empty', function() {
19421             input.clear();
19422             input.sendKeys('');
19423             expect(value.getText()).toEqual('value =');
19424             expect(valid.getText()).toContain('false');
19425           });
19426
19427           it('should be invalid if over max', function() {
19428             input.clear();
19429             input.sendKeys('123');
19430             expect(value.getText()).toEqual('value =');
19431             expect(valid.getText()).toContain('false');
19432           });
19433         </file>
19434       </example>
19435    */
19436   'number': numberInputType,
19437
19438
19439   /**
19440    * @ngdoc input
19441    * @name input[url]
19442    *
19443    * @description
19444    * Text input with URL validation. Sets the `url` validation error key if the content is not a
19445    * valid URL.
19446    *
19447    * <div class="alert alert-warning">
19448    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
19449    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
19450    * the built-in validators (see the {@link guide/forms Forms guide})
19451    * </div>
19452    *
19453    * @param {string} ngModel Assignable angular expression to data-bind to.
19454    * @param {string=} name Property name of the form under which the control is published.
19455    * @param {string=} required Sets `required` validation error key if the value is not entered.
19456    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19457    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19458    *    `required` when you want to data-bind to the `required` attribute.
19459    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19460    *    minlength.
19461    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19462    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19463    *    any length.
19464    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19465    *    that contains the regular expression body that will be converted to a regular expression
19466    *    as in the ngPattern directive.
19467    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19468    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19469    *    If the expression evaluates to a RegExp object then this is used directly.
19470    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19471    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19472    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19473    *    interaction with the input element.
19474    *
19475    * @example
19476       <example name="url-input-directive" module="urlExample">
19477         <file name="index.html">
19478          <script>
19479            angular.module('urlExample', [])
19480              .controller('ExampleController', ['$scope', function($scope) {
19481                $scope.url = {
19482                  text: 'http://google.com'
19483                };
19484              }]);
19485          </script>
19486          <form name="myForm" ng-controller="ExampleController">
19487            URL: <input type="url" name="input" ng-model="url.text" required>
19488            <span class="error" ng-show="myForm.input.$error.required">
19489              Required!</span>
19490            <span class="error" ng-show="myForm.input.$error.url">
19491              Not valid url!</span>
19492            <tt>text = {{url.text}}</tt><br/>
19493            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19494            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19495            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19496            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19497            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
19498           </form>
19499         </file>
19500         <file name="protractor.js" type="protractor">
19501           var text = element(by.binding('url.text'));
19502           var valid = element(by.binding('myForm.input.$valid'));
19503           var input = element(by.model('url.text'));
19504
19505           it('should initialize to model', function() {
19506             expect(text.getText()).toContain('http://google.com');
19507             expect(valid.getText()).toContain('true');
19508           });
19509
19510           it('should be invalid if empty', function() {
19511             input.clear();
19512             input.sendKeys('');
19513
19514             expect(text.getText()).toEqual('text =');
19515             expect(valid.getText()).toContain('false');
19516           });
19517
19518           it('should be invalid if not url', function() {
19519             input.clear();
19520             input.sendKeys('box');
19521
19522             expect(valid.getText()).toContain('false');
19523           });
19524         </file>
19525       </example>
19526    */
19527   'url': urlInputType,
19528
19529
19530   /**
19531    * @ngdoc input
19532    * @name input[email]
19533    *
19534    * @description
19535    * Text input with email validation. Sets the `email` validation error key if not a valid email
19536    * address.
19537    *
19538    * <div class="alert alert-warning">
19539    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
19540    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
19541    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
19542    * </div>
19543    *
19544    * @param {string} ngModel Assignable angular expression to data-bind to.
19545    * @param {string=} name Property name of the form under which the control is published.
19546    * @param {string=} required Sets `required` validation error key if the value is not entered.
19547    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19548    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19549    *    `required` when you want to data-bind to the `required` attribute.
19550    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19551    *    minlength.
19552    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19553    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19554    *    any length.
19555    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19556    *    that contains the regular expression body that will be converted to a regular expression
19557    *    as in the ngPattern directive.
19558    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19559    *    a RegExp found by evaluating the Angular expression given in the attribute value.
19560    *    If the expression evaluates to a RegExp object then this is used directly.
19561    *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19562    *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19563    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19564    *    interaction with the input element.
19565    *
19566    * @example
19567       <example name="email-input-directive" module="emailExample">
19568         <file name="index.html">
19569          <script>
19570            angular.module('emailExample', [])
19571              .controller('ExampleController', ['$scope', function($scope) {
19572                $scope.email = {
19573                  text: 'me@example.com'
19574                };
19575              }]);
19576          </script>
19577            <form name="myForm" ng-controller="ExampleController">
19578              Email: <input type="email" name="input" ng-model="email.text" required>
19579              <span class="error" ng-show="myForm.input.$error.required">
19580                Required!</span>
19581              <span class="error" ng-show="myForm.input.$error.email">
19582                Not valid email!</span>
19583              <tt>text = {{email.text}}</tt><br/>
19584              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19585              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19586              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19587              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19588              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
19589            </form>
19590          </file>
19591         <file name="protractor.js" type="protractor">
19592           var text = element(by.binding('email.text'));
19593           var valid = element(by.binding('myForm.input.$valid'));
19594           var input = element(by.model('email.text'));
19595
19596           it('should initialize to model', function() {
19597             expect(text.getText()).toContain('me@example.com');
19598             expect(valid.getText()).toContain('true');
19599           });
19600
19601           it('should be invalid if empty', function() {
19602             input.clear();
19603             input.sendKeys('');
19604             expect(text.getText()).toEqual('text =');
19605             expect(valid.getText()).toContain('false');
19606           });
19607
19608           it('should be invalid if not email', function() {
19609             input.clear();
19610             input.sendKeys('xxx');
19611
19612             expect(valid.getText()).toContain('false');
19613           });
19614         </file>
19615       </example>
19616    */
19617   'email': emailInputType,
19618
19619
19620   /**
19621    * @ngdoc input
19622    * @name input[radio]
19623    *
19624    * @description
19625    * HTML radio button.
19626    *
19627    * @param {string} ngModel Assignable angular expression to data-bind to.
19628    * @param {string} value The value to which the expression should be set when selected.
19629    * @param {string=} name Property name of the form under which the control is published.
19630    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19631    *    interaction with the input element.
19632    * @param {string} ngValue Angular expression which sets the value to which the expression should
19633    *    be set when selected.
19634    *
19635    * @example
19636       <example name="radio-input-directive" module="radioExample">
19637         <file name="index.html">
19638          <script>
19639            angular.module('radioExample', [])
19640              .controller('ExampleController', ['$scope', function($scope) {
19641                $scope.color = {
19642                  name: 'blue'
19643                };
19644                $scope.specialValue = {
19645                  "id": "12345",
19646                  "value": "green"
19647                };
19648              }]);
19649          </script>
19650          <form name="myForm" ng-controller="ExampleController">
19651            <input type="radio" ng-model="color.name" value="red">  Red <br/>
19652            <input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
19653            <input type="radio" ng-model="color.name" value="blue"> Blue <br/>
19654            <tt>color = {{color.name | json}}</tt><br/>
19655           </form>
19656           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
19657         </file>
19658         <file name="protractor.js" type="protractor">
19659           it('should change state', function() {
19660             var color = element(by.binding('color.name'));
19661
19662             expect(color.getText()).toContain('blue');
19663
19664             element.all(by.model('color.name')).get(0).click();
19665
19666             expect(color.getText()).toContain('red');
19667           });
19668         </file>
19669       </example>
19670    */
19671   'radio': radioInputType,
19672
19673
19674   /**
19675    * @ngdoc input
19676    * @name input[checkbox]
19677    *
19678    * @description
19679    * HTML checkbox.
19680    *
19681    * @param {string} ngModel Assignable angular expression to data-bind to.
19682    * @param {string=} name Property name of the form under which the control is published.
19683    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
19684    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
19685    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19686    *    interaction with the input element.
19687    *
19688    * @example
19689       <example name="checkbox-input-directive" module="checkboxExample">
19690         <file name="index.html">
19691          <script>
19692            angular.module('checkboxExample', [])
19693              .controller('ExampleController', ['$scope', function($scope) {
19694                $scope.checkboxModel = {
19695                 value1 : true,
19696                 value2 : 'YES'
19697               };
19698              }]);
19699          </script>
19700          <form name="myForm" ng-controller="ExampleController">
19701            Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
19702            Value2: <input type="checkbox" ng-model="checkboxModel.value2"
19703                           ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
19704            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
19705            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
19706           </form>
19707         </file>
19708         <file name="protractor.js" type="protractor">
19709           it('should change state', function() {
19710             var value1 = element(by.binding('checkboxModel.value1'));
19711             var value2 = element(by.binding('checkboxModel.value2'));
19712
19713             expect(value1.getText()).toContain('true');
19714             expect(value2.getText()).toContain('YES');
19715
19716             element(by.model('checkboxModel.value1')).click();
19717             element(by.model('checkboxModel.value2')).click();
19718
19719             expect(value1.getText()).toContain('false');
19720             expect(value2.getText()).toContain('NO');
19721           });
19722         </file>
19723       </example>
19724    */
19725   'checkbox': checkboxInputType,
19726
19727   'hidden': noop,
19728   'button': noop,
19729   'submit': noop,
19730   'reset': noop,
19731   'file': noop
19732 };
19733
19734 function stringBasedInputType(ctrl) {
19735   ctrl.$formatters.push(function(value) {
19736     return ctrl.$isEmpty(value) ? value : value.toString();
19737   });
19738 }
19739
19740 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19741   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19742   stringBasedInputType(ctrl);
19743 }
19744
19745 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19746   var type = lowercase(element[0].type);
19747
19748   // In composition mode, users are still inputing intermediate text buffer,
19749   // hold the listener until composition is done.
19750   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
19751   if (!$sniffer.android) {
19752     var composing = false;
19753
19754     element.on('compositionstart', function(data) {
19755       composing = true;
19756     });
19757
19758     element.on('compositionend', function() {
19759       composing = false;
19760       listener();
19761     });
19762   }
19763
19764   var listener = function(ev) {
19765     if (timeout) {
19766       $browser.defer.cancel(timeout);
19767       timeout = null;
19768     }
19769     if (composing) return;
19770     var value = element.val(),
19771         event = ev && ev.type;
19772
19773     // By default we will trim the value
19774     // If the attribute ng-trim exists we will avoid trimming
19775     // If input type is 'password', the value is never trimmed
19776     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
19777       value = trim(value);
19778     }
19779
19780     // If a control is suffering from bad input (due to native validators), browsers discard its
19781     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
19782     // control's value is the same empty value twice in a row.
19783     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
19784       ctrl.$setViewValue(value, event);
19785     }
19786   };
19787
19788   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
19789   // input event on backspace, delete or cut
19790   if ($sniffer.hasEvent('input')) {
19791     element.on('input', listener);
19792   } else {
19793     var timeout;
19794
19795     var deferListener = function(ev, input, origValue) {
19796       if (!timeout) {
19797         timeout = $browser.defer(function() {
19798           timeout = null;
19799           if (!input || input.value !== origValue) {
19800             listener(ev);
19801           }
19802         });
19803       }
19804     };
19805
19806     element.on('keydown', function(event) {
19807       var key = event.keyCode;
19808
19809       // ignore
19810       //    command            modifiers                   arrows
19811       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
19812
19813       deferListener(event, this, this.value);
19814     });
19815
19816     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
19817     if ($sniffer.hasEvent('paste')) {
19818       element.on('paste cut', deferListener);
19819     }
19820   }
19821
19822   // if user paste into input using mouse on older browser
19823   // or form autocomplete on newer browser, we need "change" event to catch it
19824   element.on('change', listener);
19825
19826   ctrl.$render = function() {
19827     element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
19828   };
19829 }
19830
19831 function weekParser(isoWeek, existingDate) {
19832   if (isDate(isoWeek)) {
19833     return isoWeek;
19834   }
19835
19836   if (isString(isoWeek)) {
19837     WEEK_REGEXP.lastIndex = 0;
19838     var parts = WEEK_REGEXP.exec(isoWeek);
19839     if (parts) {
19840       var year = +parts[1],
19841           week = +parts[2],
19842           hours = 0,
19843           minutes = 0,
19844           seconds = 0,
19845           milliseconds = 0,
19846           firstThurs = getFirstThursdayOfYear(year),
19847           addDays = (week - 1) * 7;
19848
19849       if (existingDate) {
19850         hours = existingDate.getHours();
19851         minutes = existingDate.getMinutes();
19852         seconds = existingDate.getSeconds();
19853         milliseconds = existingDate.getMilliseconds();
19854       }
19855
19856       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
19857     }
19858   }
19859
19860   return NaN;
19861 }
19862
19863 function createDateParser(regexp, mapping) {
19864   return function(iso, date) {
19865     var parts, map;
19866
19867     if (isDate(iso)) {
19868       return iso;
19869     }
19870
19871     if (isString(iso)) {
19872       // When a date is JSON'ified to wraps itself inside of an extra
19873       // set of double quotes. This makes the date parsing code unable
19874       // to match the date string and parse it as a date.
19875       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
19876         iso = iso.substring(1, iso.length - 1);
19877       }
19878       if (ISO_DATE_REGEXP.test(iso)) {
19879         return new Date(iso);
19880       }
19881       regexp.lastIndex = 0;
19882       parts = regexp.exec(iso);
19883
19884       if (parts) {
19885         parts.shift();
19886         if (date) {
19887           map = {
19888             yyyy: date.getFullYear(),
19889             MM: date.getMonth() + 1,
19890             dd: date.getDate(),
19891             HH: date.getHours(),
19892             mm: date.getMinutes(),
19893             ss: date.getSeconds(),
19894             sss: date.getMilliseconds() / 1000
19895           };
19896         } else {
19897           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
19898         }
19899
19900         forEach(parts, function(part, index) {
19901           if (index < mapping.length) {
19902             map[mapping[index]] = +part;
19903           }
19904         });
19905         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
19906       }
19907     }
19908
19909     return NaN;
19910   };
19911 }
19912
19913 function createDateInputType(type, regexp, parseDate, format) {
19914   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
19915     badInputChecker(scope, element, attr, ctrl);
19916     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19917     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
19918     var previousDate;
19919
19920     ctrl.$$parserName = type;
19921     ctrl.$parsers.push(function(value) {
19922       if (ctrl.$isEmpty(value)) return null;
19923       if (regexp.test(value)) {
19924         // Note: We cannot read ctrl.$modelValue, as there might be a different
19925         // parser/formatter in the processing chain so that the model
19926         // contains some different data format!
19927         var parsedDate = parseDate(value, previousDate);
19928         if (timezone === 'UTC') {
19929           parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
19930         }
19931         return parsedDate;
19932       }
19933       return undefined;
19934     });
19935
19936     ctrl.$formatters.push(function(value) {
19937       if (value && !isDate(value)) {
19938         throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19939       }
19940       if (isValidDate(value)) {
19941         previousDate = value;
19942         if (previousDate && timezone === 'UTC') {
19943           var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
19944           previousDate = new Date(previousDate.getTime() + timezoneOffset);
19945         }
19946         return $filter('date')(value, format, timezone);
19947       } else {
19948         previousDate = null;
19949         return '';
19950       }
19951     });
19952
19953     if (isDefined(attr.min) || attr.ngMin) {
19954       var minVal;
19955       ctrl.$validators.min = function(value) {
19956         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19957       };
19958       attr.$observe('min', function(val) {
19959         minVal = parseObservedDateValue(val);
19960         ctrl.$validate();
19961       });
19962     }
19963
19964     if (isDefined(attr.max) || attr.ngMax) {
19965       var maxVal;
19966       ctrl.$validators.max = function(value) {
19967         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19968       };
19969       attr.$observe('max', function(val) {
19970         maxVal = parseObservedDateValue(val);
19971         ctrl.$validate();
19972       });
19973     }
19974
19975     function isValidDate(value) {
19976       // Invalid Date: getTime() returns NaN
19977       return value && !(value.getTime && value.getTime() !== value.getTime());
19978     }
19979
19980     function parseObservedDateValue(val) {
19981       return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
19982     }
19983   };
19984 }
19985
19986 function badInputChecker(scope, element, attr, ctrl) {
19987   var node = element[0];
19988   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
19989   if (nativeValidation) {
19990     ctrl.$parsers.push(function(value) {
19991       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
19992       // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
19993       // - also sets validity.badInput (should only be validity.typeMismatch).
19994       // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
19995       // - can ignore this case as we can still read out the erroneous email...
19996       return validity.badInput && !validity.typeMismatch ? undefined : value;
19997     });
19998   }
19999 }
20000
20001 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20002   badInputChecker(scope, element, attr, ctrl);
20003   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20004
20005   ctrl.$$parserName = 'number';
20006   ctrl.$parsers.push(function(value) {
20007     if (ctrl.$isEmpty(value))      return null;
20008     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
20009     return undefined;
20010   });
20011
20012   ctrl.$formatters.push(function(value) {
20013     if (!ctrl.$isEmpty(value)) {
20014       if (!isNumber(value)) {
20015         throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
20016       }
20017       value = value.toString();
20018     }
20019     return value;
20020   });
20021
20022   if (isDefined(attr.min) || attr.ngMin) {
20023     var minVal;
20024     ctrl.$validators.min = function(value) {
20025       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
20026     };
20027
20028     attr.$observe('min', function(val) {
20029       if (isDefined(val) && !isNumber(val)) {
20030         val = parseFloat(val, 10);
20031       }
20032       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
20033       // TODO(matsko): implement validateLater to reduce number of validations
20034       ctrl.$validate();
20035     });
20036   }
20037
20038   if (isDefined(attr.max) || attr.ngMax) {
20039     var maxVal;
20040     ctrl.$validators.max = function(value) {
20041       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
20042     };
20043
20044     attr.$observe('max', function(val) {
20045       if (isDefined(val) && !isNumber(val)) {
20046         val = parseFloat(val, 10);
20047       }
20048       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
20049       // TODO(matsko): implement validateLater to reduce number of validations
20050       ctrl.$validate();
20051     });
20052   }
20053 }
20054
20055 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20056   // Note: no badInputChecker here by purpose as `url` is only a validation
20057   // in browsers, i.e. we can always read out input.value even if it is not valid!
20058   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20059   stringBasedInputType(ctrl);
20060
20061   ctrl.$$parserName = 'url';
20062   ctrl.$validators.url = function(modelValue, viewValue) {
20063     var value = modelValue || viewValue;
20064     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
20065   };
20066 }
20067
20068 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
20069   // Note: no badInputChecker here by purpose as `url` is only a validation
20070   // in browsers, i.e. we can always read out input.value even if it is not valid!
20071   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
20072   stringBasedInputType(ctrl);
20073
20074   ctrl.$$parserName = 'email';
20075   ctrl.$validators.email = function(modelValue, viewValue) {
20076     var value = modelValue || viewValue;
20077     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
20078   };
20079 }
20080
20081 function radioInputType(scope, element, attr, ctrl) {
20082   // make the name unique, if not defined
20083   if (isUndefined(attr.name)) {
20084     element.attr('name', nextUid());
20085   }
20086
20087   var listener = function(ev) {
20088     if (element[0].checked) {
20089       ctrl.$setViewValue(attr.value, ev && ev.type);
20090     }
20091   };
20092
20093   element.on('click', listener);
20094
20095   ctrl.$render = function() {
20096     var value = attr.value;
20097     element[0].checked = (value == ctrl.$viewValue);
20098   };
20099
20100   attr.$observe('value', ctrl.$render);
20101 }
20102
20103 function parseConstantExpr($parse, context, name, expression, fallback) {
20104   var parseFn;
20105   if (isDefined(expression)) {
20106     parseFn = $parse(expression);
20107     if (!parseFn.constant) {
20108       throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
20109                                    '`{1}`.', name, expression);
20110     }
20111     return parseFn(context);
20112   }
20113   return fallback;
20114 }
20115
20116 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
20117   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
20118   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
20119
20120   var listener = function(ev) {
20121     ctrl.$setViewValue(element[0].checked, ev && ev.type);
20122   };
20123
20124   element.on('click', listener);
20125
20126   ctrl.$render = function() {
20127     element[0].checked = ctrl.$viewValue;
20128   };
20129
20130   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
20131   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
20132   // it to a boolean.
20133   ctrl.$isEmpty = function(value) {
20134     return value === false;
20135   };
20136
20137   ctrl.$formatters.push(function(value) {
20138     return equals(value, trueValue);
20139   });
20140
20141   ctrl.$parsers.push(function(value) {
20142     return value ? trueValue : falseValue;
20143   });
20144 }
20145
20146
20147 /**
20148  * @ngdoc directive
20149  * @name textarea
20150  * @restrict E
20151  *
20152  * @description
20153  * HTML textarea element control with angular data-binding. The data-binding and validation
20154  * properties of this element are exactly the same as those of the
20155  * {@link ng.directive:input input element}.
20156  *
20157  * @param {string} ngModel Assignable angular expression to data-bind to.
20158  * @param {string=} name Property name of the form under which the control is published.
20159  * @param {string=} required Sets `required` validation error key if the value is not entered.
20160  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20161  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20162  *    `required` when you want to data-bind to the `required` attribute.
20163  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20164  *    minlength.
20165  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20166  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20167  *    length.
20168  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20169  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20170  *    patterns defined as scope expressions.
20171  * @param {string=} ngChange Angular expression to be executed when input changes due to user
20172  *    interaction with the input element.
20173  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20174  */
20175
20176
20177 /**
20178  * @ngdoc directive
20179  * @name input
20180  * @restrict E
20181  *
20182  * @description
20183  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
20184  * input state control, and validation.
20185  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
20186  *
20187  * <div class="alert alert-warning">
20188  * **Note:** Not every feature offered is available for all input types.
20189  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
20190  * </div>
20191  *
20192  * @param {string} ngModel Assignable angular expression to data-bind to.
20193  * @param {string=} name Property name of the form under which the control is published.
20194  * @param {string=} required Sets `required` validation error key if the value is not entered.
20195  * @param {boolean=} ngRequired Sets `required` attribute if set to true
20196  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20197  *    minlength.
20198  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20199  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20200  *    length.
20201  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20202  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20203  *    patterns defined as scope expressions.
20204  * @param {string=} ngChange Angular expression to be executed when input changes due to user
20205  *    interaction with the input element.
20206  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20207  *    This parameter is ignored for input[type=password] controls, which will never trim the
20208  *    input.
20209  *
20210  * @example
20211     <example name="input-directive" module="inputExample">
20212       <file name="index.html">
20213        <script>
20214           angular.module('inputExample', [])
20215             .controller('ExampleController', ['$scope', function($scope) {
20216               $scope.user = {name: 'guest', last: 'visitor'};
20217             }]);
20218        </script>
20219        <div ng-controller="ExampleController">
20220          <form name="myForm">
20221            User name: <input type="text" name="userName" ng-model="user.name" required>
20222            <span class="error" ng-show="myForm.userName.$error.required">
20223              Required!</span><br>
20224            Last name: <input type="text" name="lastName" ng-model="user.last"
20225              ng-minlength="3" ng-maxlength="10">
20226            <span class="error" ng-show="myForm.lastName.$error.minlength">
20227              Too short!</span>
20228            <span class="error" ng-show="myForm.lastName.$error.maxlength">
20229              Too long!</span><br>
20230          </form>
20231          <hr>
20232          <tt>user = {{user}}</tt><br/>
20233          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
20234          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
20235          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
20236          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
20237          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
20238          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
20239          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
20240          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
20241        </div>
20242       </file>
20243       <file name="protractor.js" type="protractor">
20244         var user = element(by.exactBinding('user'));
20245         var userNameValid = element(by.binding('myForm.userName.$valid'));
20246         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
20247         var lastNameError = element(by.binding('myForm.lastName.$error'));
20248         var formValid = element(by.binding('myForm.$valid'));
20249         var userNameInput = element(by.model('user.name'));
20250         var userLastInput = element(by.model('user.last'));
20251
20252         it('should initialize to model', function() {
20253           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
20254           expect(userNameValid.getText()).toContain('true');
20255           expect(formValid.getText()).toContain('true');
20256         });
20257
20258         it('should be invalid if empty when required', function() {
20259           userNameInput.clear();
20260           userNameInput.sendKeys('');
20261
20262           expect(user.getText()).toContain('{"last":"visitor"}');
20263           expect(userNameValid.getText()).toContain('false');
20264           expect(formValid.getText()).toContain('false');
20265         });
20266
20267         it('should be valid if empty when min length is set', function() {
20268           userLastInput.clear();
20269           userLastInput.sendKeys('');
20270
20271           expect(user.getText()).toContain('{"name":"guest","last":""}');
20272           expect(lastNameValid.getText()).toContain('true');
20273           expect(formValid.getText()).toContain('true');
20274         });
20275
20276         it('should be invalid if less than required min length', function() {
20277           userLastInput.clear();
20278           userLastInput.sendKeys('xx');
20279
20280           expect(user.getText()).toContain('{"name":"guest"}');
20281           expect(lastNameValid.getText()).toContain('false');
20282           expect(lastNameError.getText()).toContain('minlength');
20283           expect(formValid.getText()).toContain('false');
20284         });
20285
20286         it('should be invalid if longer than max length', function() {
20287           userLastInput.clear();
20288           userLastInput.sendKeys('some ridiculously long name');
20289
20290           expect(user.getText()).toContain('{"name":"guest"}');
20291           expect(lastNameValid.getText()).toContain('false');
20292           expect(lastNameError.getText()).toContain('maxlength');
20293           expect(formValid.getText()).toContain('false');
20294         });
20295       </file>
20296     </example>
20297  */
20298 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
20299     function($browser, $sniffer, $filter, $parse) {
20300   return {
20301     restrict: 'E',
20302     require: ['?ngModel'],
20303     link: {
20304       pre: function(scope, element, attr, ctrls) {
20305         if (ctrls[0]) {
20306           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
20307                                                               $browser, $filter, $parse);
20308         }
20309       }
20310     }
20311   };
20312 }];
20313
20314
20315
20316 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
20317 /**
20318  * @ngdoc directive
20319  * @name ngValue
20320  *
20321  * @description
20322  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
20323  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
20324  * the bound value.
20325  *
20326  * `ngValue` is useful when dynamically generating lists of radio buttons using
20327  * {@link ngRepeat `ngRepeat`}, as shown below.
20328  *
20329  * Likewise, `ngValue` can be used to generate `<option>` elements for
20330  * the {@link select `select`} element. In that case however, only strings are supported
20331  * for the `value `attribute, so the resulting `ngModel` will always be a string.
20332  * Support for `select` models with non-string values is available via `ngOptions`.
20333  *
20334  * @element input
20335  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
20336  *   of the `input` element
20337  *
20338  * @example
20339     <example name="ngValue-directive" module="valueExample">
20340       <file name="index.html">
20341        <script>
20342           angular.module('valueExample', [])
20343             .controller('ExampleController', ['$scope', function($scope) {
20344               $scope.names = ['pizza', 'unicorns', 'robots'];
20345               $scope.my = { favorite: 'unicorns' };
20346             }]);
20347        </script>
20348         <form ng-controller="ExampleController">
20349           <h2>Which is your favorite?</h2>
20350             <label ng-repeat="name in names" for="{{name}}">
20351               {{name}}
20352               <input type="radio"
20353                      ng-model="my.favorite"
20354                      ng-value="name"
20355                      id="{{name}}"
20356                      name="favorite">
20357             </label>
20358           <div>You chose {{my.favorite}}</div>
20359         </form>
20360       </file>
20361       <file name="protractor.js" type="protractor">
20362         var favorite = element(by.binding('my.favorite'));
20363
20364         it('should initialize to model', function() {
20365           expect(favorite.getText()).toContain('unicorns');
20366         });
20367         it('should bind the values to the inputs', function() {
20368           element.all(by.model('my.favorite')).get(0).click();
20369           expect(favorite.getText()).toContain('pizza');
20370         });
20371       </file>
20372     </example>
20373  */
20374 var ngValueDirective = function() {
20375   return {
20376     restrict: 'A',
20377     priority: 100,
20378     compile: function(tpl, tplAttr) {
20379       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
20380         return function ngValueConstantLink(scope, elm, attr) {
20381           attr.$set('value', scope.$eval(attr.ngValue));
20382         };
20383       } else {
20384         return function ngValueLink(scope, elm, attr) {
20385           scope.$watch(attr.ngValue, function valueWatchAction(value) {
20386             attr.$set('value', value);
20387           });
20388         };
20389       }
20390     }
20391   };
20392 };
20393
20394 /**
20395  * @ngdoc directive
20396  * @name ngBind
20397  * @restrict AC
20398  *
20399  * @description
20400  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
20401  * with the value of a given expression, and to update the text content when the value of that
20402  * expression changes.
20403  *
20404  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
20405  * `{{ expression }}` which is similar but less verbose.
20406  *
20407  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
20408  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
20409  * element attribute, it makes the bindings invisible to the user while the page is loading.
20410  *
20411  * An alternative solution to this problem would be using the
20412  * {@link ng.directive:ngCloak ngCloak} directive.
20413  *
20414  *
20415  * @element ANY
20416  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
20417  *
20418  * @example
20419  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
20420    <example module="bindExample">
20421      <file name="index.html">
20422        <script>
20423          angular.module('bindExample', [])
20424            .controller('ExampleController', ['$scope', function($scope) {
20425              $scope.name = 'Whirled';
20426            }]);
20427        </script>
20428        <div ng-controller="ExampleController">
20429          Enter name: <input type="text" ng-model="name"><br>
20430          Hello <span ng-bind="name"></span>!
20431        </div>
20432      </file>
20433      <file name="protractor.js" type="protractor">
20434        it('should check ng-bind', function() {
20435          var nameInput = element(by.model('name'));
20436
20437          expect(element(by.binding('name')).getText()).toBe('Whirled');
20438          nameInput.clear();
20439          nameInput.sendKeys('world');
20440          expect(element(by.binding('name')).getText()).toBe('world');
20441        });
20442      </file>
20443    </example>
20444  */
20445 var ngBindDirective = ['$compile', function($compile) {
20446   return {
20447     restrict: 'AC',
20448     compile: function ngBindCompile(templateElement) {
20449       $compile.$$addBindingClass(templateElement);
20450       return function ngBindLink(scope, element, attr) {
20451         $compile.$$addBindingInfo(element, attr.ngBind);
20452         element = element[0];
20453         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
20454           element.textContent = value === undefined ? '' : value;
20455         });
20456       };
20457     }
20458   };
20459 }];
20460
20461
20462 /**
20463  * @ngdoc directive
20464  * @name ngBindTemplate
20465  *
20466  * @description
20467  * The `ngBindTemplate` directive specifies that the element
20468  * text content should be replaced with the interpolation of the template
20469  * in the `ngBindTemplate` attribute.
20470  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
20471  * expressions. This directive is needed since some HTML elements
20472  * (such as TITLE and OPTION) cannot contain SPAN elements.
20473  *
20474  * @element ANY
20475  * @param {string} ngBindTemplate template of form
20476  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
20477  *
20478  * @example
20479  * Try it here: enter text in text box and watch the greeting change.
20480    <example module="bindExample">
20481      <file name="index.html">
20482        <script>
20483          angular.module('bindExample', [])
20484            .controller('ExampleController', ['$scope', function($scope) {
20485              $scope.salutation = 'Hello';
20486              $scope.name = 'World';
20487            }]);
20488        </script>
20489        <div ng-controller="ExampleController">
20490         Salutation: <input type="text" ng-model="salutation"><br>
20491         Name: <input type="text" ng-model="name"><br>
20492         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
20493        </div>
20494      </file>
20495      <file name="protractor.js" type="protractor">
20496        it('should check ng-bind', function() {
20497          var salutationElem = element(by.binding('salutation'));
20498          var salutationInput = element(by.model('salutation'));
20499          var nameInput = element(by.model('name'));
20500
20501          expect(salutationElem.getText()).toBe('Hello World!');
20502
20503          salutationInput.clear();
20504          salutationInput.sendKeys('Greetings');
20505          nameInput.clear();
20506          nameInput.sendKeys('user');
20507
20508          expect(salutationElem.getText()).toBe('Greetings user!');
20509        });
20510      </file>
20511    </example>
20512  */
20513 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
20514   return {
20515     compile: function ngBindTemplateCompile(templateElement) {
20516       $compile.$$addBindingClass(templateElement);
20517       return function ngBindTemplateLink(scope, element, attr) {
20518         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
20519         $compile.$$addBindingInfo(element, interpolateFn.expressions);
20520         element = element[0];
20521         attr.$observe('ngBindTemplate', function(value) {
20522           element.textContent = value === undefined ? '' : value;
20523         });
20524       };
20525     }
20526   };
20527 }];
20528
20529
20530 /**
20531  * @ngdoc directive
20532  * @name ngBindHtml
20533  *
20534  * @description
20535  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
20536  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
20537  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
20538  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
20539  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
20540  *
20541  * You may also bypass sanitization for values you know are safe. To do so, bind to
20542  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
20543  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
20544  *
20545  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
20546  * will have an exception (instead of an exploit.)
20547  *
20548  * @element ANY
20549  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
20550  *
20551  * @example
20552
20553    <example module="bindHtmlExample" deps="angular-sanitize.js">
20554      <file name="index.html">
20555        <div ng-controller="ExampleController">
20556         <p ng-bind-html="myHTML"></p>
20557        </div>
20558      </file>
20559
20560      <file name="script.js">
20561        angular.module('bindHtmlExample', ['ngSanitize'])
20562          .controller('ExampleController', ['$scope', function($scope) {
20563            $scope.myHTML =
20564               'I am an <code>HTML</code>string with ' +
20565               '<a href="#">links!</a> and other <em>stuff</em>';
20566          }]);
20567      </file>
20568
20569      <file name="protractor.js" type="protractor">
20570        it('should check ng-bind-html', function() {
20571          expect(element(by.binding('myHTML')).getText()).toBe(
20572              'I am an HTMLstring with links! and other stuff');
20573        });
20574      </file>
20575    </example>
20576  */
20577 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
20578   return {
20579     restrict: 'A',
20580     compile: function ngBindHtmlCompile(tElement, tAttrs) {
20581       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
20582       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
20583         return (value || '').toString();
20584       });
20585       $compile.$$addBindingClass(tElement);
20586
20587       return function ngBindHtmlLink(scope, element, attr) {
20588         $compile.$$addBindingInfo(element, attr.ngBindHtml);
20589
20590         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
20591           // we re-evaluate the expr because we want a TrustedValueHolderType
20592           // for $sce, not a string
20593           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
20594         });
20595       };
20596     }
20597   };
20598 }];
20599
20600 /**
20601  * @ngdoc directive
20602  * @name ngChange
20603  *
20604  * @description
20605  * Evaluate the given expression when the user changes the input.
20606  * The expression is evaluated immediately, unlike the JavaScript onchange event
20607  * which only triggers at the end of a change (usually, when the user leaves the
20608  * form element or presses the return key).
20609  *
20610  * The `ngChange` expression is only evaluated when a change in the input value causes
20611  * a new value to be committed to the model.
20612  *
20613  * It will not be evaluated:
20614  * * if the value returned from the `$parsers` transformation pipeline has not changed
20615  * * if the input has continued to be invalid since the model will stay `null`
20616  * * if the model is changed programmatically and not by a change to the input value
20617  *
20618  *
20619  * Note, this directive requires `ngModel` to be present.
20620  *
20621  * @element input
20622  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
20623  * in input value.
20624  *
20625  * @example
20626  * <example name="ngChange-directive" module="changeExample">
20627  *   <file name="index.html">
20628  *     <script>
20629  *       angular.module('changeExample', [])
20630  *         .controller('ExampleController', ['$scope', function($scope) {
20631  *           $scope.counter = 0;
20632  *           $scope.change = function() {
20633  *             $scope.counter++;
20634  *           };
20635  *         }]);
20636  *     </script>
20637  *     <div ng-controller="ExampleController">
20638  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
20639  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
20640  *       <label for="ng-change-example2">Confirmed</label><br />
20641  *       <tt>debug = {{confirmed}}</tt><br/>
20642  *       <tt>counter = {{counter}}</tt><br/>
20643  *     </div>
20644  *   </file>
20645  *   <file name="protractor.js" type="protractor">
20646  *     var counter = element(by.binding('counter'));
20647  *     var debug = element(by.binding('confirmed'));
20648  *
20649  *     it('should evaluate the expression if changing from view', function() {
20650  *       expect(counter.getText()).toContain('0');
20651  *
20652  *       element(by.id('ng-change-example1')).click();
20653  *
20654  *       expect(counter.getText()).toContain('1');
20655  *       expect(debug.getText()).toContain('true');
20656  *     });
20657  *
20658  *     it('should not evaluate the expression if changing from model', function() {
20659  *       element(by.id('ng-change-example2')).click();
20660
20661  *       expect(counter.getText()).toContain('0');
20662  *       expect(debug.getText()).toContain('true');
20663  *     });
20664  *   </file>
20665  * </example>
20666  */
20667 var ngChangeDirective = valueFn({
20668   restrict: 'A',
20669   require: 'ngModel',
20670   link: function(scope, element, attr, ctrl) {
20671     ctrl.$viewChangeListeners.push(function() {
20672       scope.$eval(attr.ngChange);
20673     });
20674   }
20675 });
20676
20677 function classDirective(name, selector) {
20678   name = 'ngClass' + name;
20679   return ['$animate', function($animate) {
20680     return {
20681       restrict: 'AC',
20682       link: function(scope, element, attr) {
20683         var oldVal;
20684
20685         scope.$watch(attr[name], ngClassWatchAction, true);
20686
20687         attr.$observe('class', function(value) {
20688           ngClassWatchAction(scope.$eval(attr[name]));
20689         });
20690
20691
20692         if (name !== 'ngClass') {
20693           scope.$watch('$index', function($index, old$index) {
20694             // jshint bitwise: false
20695             var mod = $index & 1;
20696             if (mod !== (old$index & 1)) {
20697               var classes = arrayClasses(scope.$eval(attr[name]));
20698               mod === selector ?
20699                 addClasses(classes) :
20700                 removeClasses(classes);
20701             }
20702           });
20703         }
20704
20705         function addClasses(classes) {
20706           var newClasses = digestClassCounts(classes, 1);
20707           attr.$addClass(newClasses);
20708         }
20709
20710         function removeClasses(classes) {
20711           var newClasses = digestClassCounts(classes, -1);
20712           attr.$removeClass(newClasses);
20713         }
20714
20715         function digestClassCounts(classes, count) {
20716           var classCounts = element.data('$classCounts') || {};
20717           var classesToUpdate = [];
20718           forEach(classes, function(className) {
20719             if (count > 0 || classCounts[className]) {
20720               classCounts[className] = (classCounts[className] || 0) + count;
20721               if (classCounts[className] === +(count > 0)) {
20722                 classesToUpdate.push(className);
20723               }
20724             }
20725           });
20726           element.data('$classCounts', classCounts);
20727           return classesToUpdate.join(' ');
20728         }
20729
20730         function updateClasses(oldClasses, newClasses) {
20731           var toAdd = arrayDifference(newClasses, oldClasses);
20732           var toRemove = arrayDifference(oldClasses, newClasses);
20733           toAdd = digestClassCounts(toAdd, 1);
20734           toRemove = digestClassCounts(toRemove, -1);
20735           if (toAdd && toAdd.length) {
20736             $animate.addClass(element, toAdd);
20737           }
20738           if (toRemove && toRemove.length) {
20739             $animate.removeClass(element, toRemove);
20740           }
20741         }
20742
20743         function ngClassWatchAction(newVal) {
20744           if (selector === true || scope.$index % 2 === selector) {
20745             var newClasses = arrayClasses(newVal || []);
20746             if (!oldVal) {
20747               addClasses(newClasses);
20748             } else if (!equals(newVal,oldVal)) {
20749               var oldClasses = arrayClasses(oldVal);
20750               updateClasses(oldClasses, newClasses);
20751             }
20752           }
20753           oldVal = shallowCopy(newVal);
20754         }
20755       }
20756     };
20757
20758     function arrayDifference(tokens1, tokens2) {
20759       var values = [];
20760
20761       outer:
20762       for (var i = 0; i < tokens1.length; i++) {
20763         var token = tokens1[i];
20764         for (var j = 0; j < tokens2.length; j++) {
20765           if (token == tokens2[j]) continue outer;
20766         }
20767         values.push(token);
20768       }
20769       return values;
20770     }
20771
20772     function arrayClasses(classVal) {
20773       if (isArray(classVal)) {
20774         return classVal;
20775       } else if (isString(classVal)) {
20776         return classVal.split(' ');
20777       } else if (isObject(classVal)) {
20778         var classes = [];
20779         forEach(classVal, function(v, k) {
20780           if (v) {
20781             classes = classes.concat(k.split(' '));
20782           }
20783         });
20784         return classes;
20785       }
20786       return classVal;
20787     }
20788   }];
20789 }
20790
20791 /**
20792  * @ngdoc directive
20793  * @name ngClass
20794  * @restrict AC
20795  *
20796  * @description
20797  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
20798  * an expression that represents all classes to be added.
20799  *
20800  * The directive operates in three different ways, depending on which of three types the expression
20801  * evaluates to:
20802  *
20803  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
20804  * names.
20805  *
20806  * 2. If the expression evaluates to an array, each element of the array should be a string that is
20807  * one or more space-delimited class names.
20808  *
20809  * 3. If the expression evaluates to an object, then for each key-value pair of the
20810  * object with a truthy value the corresponding key is used as a class name.
20811  *
20812  * The directive won't add duplicate classes if a particular class was already set.
20813  *
20814  * When the expression changes, the previously added classes are removed and only then the
20815  * new classes are added.
20816  *
20817  * @animations
20818  * **add** - happens just before the class is applied to the elements
20819  *
20820  * **remove** - happens just before the class is removed from the element
20821  *
20822  * @element ANY
20823  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
20824  *   of the evaluation can be a string representing space delimited class
20825  *   names, an array, or a map of class names to boolean values. In the case of a map, the
20826  *   names of the properties whose values are truthy will be added as css classes to the
20827  *   element.
20828  *
20829  * @example Example that demonstrates basic bindings via ngClass directive.
20830    <example>
20831      <file name="index.html">
20832        <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
20833        <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
20834        <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
20835        <input type="checkbox" ng-model="error"> error (apply "red" class)
20836        <hr>
20837        <p ng-class="style">Using String Syntax</p>
20838        <input type="text" ng-model="style" placeholder="Type: bold strike red">
20839        <hr>
20840        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
20841        <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
20842        <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
20843        <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
20844      </file>
20845      <file name="style.css">
20846        .strike {
20847          text-decoration: line-through;
20848        }
20849        .bold {
20850            font-weight: bold;
20851        }
20852        .red {
20853            color: red;
20854        }
20855      </file>
20856      <file name="protractor.js" type="protractor">
20857        var ps = element.all(by.css('p'));
20858
20859        it('should let you toggle the class', function() {
20860
20861          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
20862          expect(ps.first().getAttribute('class')).not.toMatch(/red/);
20863
20864          element(by.model('important')).click();
20865          expect(ps.first().getAttribute('class')).toMatch(/bold/);
20866
20867          element(by.model('error')).click();
20868          expect(ps.first().getAttribute('class')).toMatch(/red/);
20869        });
20870
20871        it('should let you toggle string example', function() {
20872          expect(ps.get(1).getAttribute('class')).toBe('');
20873          element(by.model('style')).clear();
20874          element(by.model('style')).sendKeys('red');
20875          expect(ps.get(1).getAttribute('class')).toBe('red');
20876        });
20877
20878        it('array example should have 3 classes', function() {
20879          expect(ps.last().getAttribute('class')).toBe('');
20880          element(by.model('style1')).sendKeys('bold');
20881          element(by.model('style2')).sendKeys('strike');
20882          element(by.model('style3')).sendKeys('red');
20883          expect(ps.last().getAttribute('class')).toBe('bold strike red');
20884        });
20885      </file>
20886    </example>
20887
20888    ## Animations
20889
20890    The example below demonstrates how to perform animations using ngClass.
20891
20892    <example module="ngAnimate" deps="angular-animate.js" animations="true">
20893      <file name="index.html">
20894       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
20895       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
20896       <br>
20897       <span class="base-class" ng-class="myVar">Sample Text</span>
20898      </file>
20899      <file name="style.css">
20900        .base-class {
20901          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20902          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20903        }
20904
20905        .base-class.my-class {
20906          color: red;
20907          font-size:3em;
20908        }
20909      </file>
20910      <file name="protractor.js" type="protractor">
20911        it('should check ng-class', function() {
20912          expect(element(by.css('.base-class')).getAttribute('class')).not.
20913            toMatch(/my-class/);
20914
20915          element(by.id('setbtn')).click();
20916
20917          expect(element(by.css('.base-class')).getAttribute('class')).
20918            toMatch(/my-class/);
20919
20920          element(by.id('clearbtn')).click();
20921
20922          expect(element(by.css('.base-class')).getAttribute('class')).not.
20923            toMatch(/my-class/);
20924        });
20925      </file>
20926    </example>
20927
20928
20929    ## ngClass and pre-existing CSS3 Transitions/Animations
20930    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
20931    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
20932    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
20933    to view the step by step details of {@link ng.$animate#addClass $animate.addClass} and
20934    {@link ng.$animate#removeClass $animate.removeClass}.
20935  */
20936 var ngClassDirective = classDirective('', true);
20937
20938 /**
20939  * @ngdoc directive
20940  * @name ngClassOdd
20941  * @restrict AC
20942  *
20943  * @description
20944  * The `ngClassOdd` and `ngClassEven` directives work exactly as
20945  * {@link ng.directive:ngClass ngClass}, except they work in
20946  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
20947  *
20948  * This directive can be applied only within the scope of an
20949  * {@link ng.directive:ngRepeat ngRepeat}.
20950  *
20951  * @element ANY
20952  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
20953  *   of the evaluation can be a string representing space delimited class names or an array.
20954  *
20955  * @example
20956    <example>
20957      <file name="index.html">
20958         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
20959           <li ng-repeat="name in names">
20960            <span ng-class-odd="'odd'" ng-class-even="'even'">
20961              {{name}}
20962            </span>
20963           </li>
20964         </ol>
20965      </file>
20966      <file name="style.css">
20967        .odd {
20968          color: red;
20969        }
20970        .even {
20971          color: blue;
20972        }
20973      </file>
20974      <file name="protractor.js" type="protractor">
20975        it('should check ng-class-odd and ng-class-even', function() {
20976          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
20977            toMatch(/odd/);
20978          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
20979            toMatch(/even/);
20980        });
20981      </file>
20982    </example>
20983  */
20984 var ngClassOddDirective = classDirective('Odd', 0);
20985
20986 /**
20987  * @ngdoc directive
20988  * @name ngClassEven
20989  * @restrict AC
20990  *
20991  * @description
20992  * The `ngClassOdd` and `ngClassEven` directives work exactly as
20993  * {@link ng.directive:ngClass ngClass}, except they work in
20994  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
20995  *
20996  * This directive can be applied only within the scope of an
20997  * {@link ng.directive:ngRepeat ngRepeat}.
20998  *
20999  * @element ANY
21000  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
21001  *   result of the evaluation can be a string representing space delimited class names or an array.
21002  *
21003  * @example
21004    <example>
21005      <file name="index.html">
21006         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
21007           <li ng-repeat="name in names">
21008            <span ng-class-odd="'odd'" ng-class-even="'even'">
21009              {{name}} &nbsp; &nbsp; &nbsp;
21010            </span>
21011           </li>
21012         </ol>
21013      </file>
21014      <file name="style.css">
21015        .odd {
21016          color: red;
21017        }
21018        .even {
21019          color: blue;
21020        }
21021      </file>
21022      <file name="protractor.js" type="protractor">
21023        it('should check ng-class-odd and ng-class-even', function() {
21024          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
21025            toMatch(/odd/);
21026          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
21027            toMatch(/even/);
21028        });
21029      </file>
21030    </example>
21031  */
21032 var ngClassEvenDirective = classDirective('Even', 1);
21033
21034 /**
21035  * @ngdoc directive
21036  * @name ngCloak
21037  * @restrict AC
21038  *
21039  * @description
21040  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
21041  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
21042  * directive to avoid the undesirable flicker effect caused by the html template display.
21043  *
21044  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
21045  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
21046  * of the browser view.
21047  *
21048  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
21049  * `angular.min.js`.
21050  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
21051  *
21052  * ```css
21053  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
21054  *   display: none !important;
21055  * }
21056  * ```
21057  *
21058  * When this css rule is loaded by the browser, all html elements (including their children) that
21059  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
21060  * during the compilation of the template it deletes the `ngCloak` element attribute, making
21061  * the compiled element visible.
21062  *
21063  * For the best result, the `angular.js` script must be loaded in the head section of the html
21064  * document; alternatively, the css rule above must be included in the external stylesheet of the
21065  * application.
21066  *
21067  * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
21068  * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
21069  * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
21070  *
21071  * @element ANY
21072  *
21073  * @example
21074    <example>
21075      <file name="index.html">
21076         <div id="template1" ng-cloak>{{ 'hello' }}</div>
21077         <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
21078      </file>
21079      <file name="protractor.js" type="protractor">
21080        it('should remove the template directive and css class', function() {
21081          expect($('#template1').getAttribute('ng-cloak')).
21082            toBeNull();
21083          expect($('#template2').getAttribute('ng-cloak')).
21084            toBeNull();
21085        });
21086      </file>
21087    </example>
21088  *
21089  */
21090 var ngCloakDirective = ngDirective({
21091   compile: function(element, attr) {
21092     attr.$set('ngCloak', undefined);
21093     element.removeClass('ng-cloak');
21094   }
21095 });
21096
21097 /**
21098  * @ngdoc directive
21099  * @name ngController
21100  *
21101  * @description
21102  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
21103  * supports the principles behind the Model-View-Controller design pattern.
21104  *
21105  * MVC components in angular:
21106  *
21107  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
21108  *   are accessed through bindings.
21109  * * View — The template (HTML with data bindings) that is rendered into the View.
21110  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
21111  *   logic behind the application to decorate the scope with functions and values
21112  *
21113  * Note that you can also attach controllers to the DOM by declaring it in a route definition
21114  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
21115  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
21116  * and executed twice.
21117  *
21118  * @element ANY
21119  * @scope
21120  * @priority 500
21121  * @param {expression} ngController Name of a constructor function registered with the current
21122  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
21123  * that on the current scope evaluates to a constructor function.
21124  *
21125  * The controller instance can be published into a scope property by specifying
21126  * `ng-controller="as propertyName"`.
21127  *
21128  * If the current `$controllerProvider` is configured to use globals (via
21129  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
21130  * also be the name of a globally accessible constructor function (not recommended).
21131  *
21132  * @example
21133  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
21134  * greeting are methods declared on the controller (see source tab). These methods can
21135  * easily be called from the angular markup. Any changes to the data are automatically reflected
21136  * in the View without the need for a manual update.
21137  *
21138  * Two different declaration styles are included below:
21139  *
21140  * * one binds methods and properties directly onto the controller using `this`:
21141  * `ng-controller="SettingsController1 as settings"`
21142  * * one injects `$scope` into the controller:
21143  * `ng-controller="SettingsController2"`
21144  *
21145  * The second option is more common in the Angular community, and is generally used in boilerplates
21146  * and in this guide. However, there are advantages to binding properties directly to the controller
21147  * and avoiding scope.
21148  *
21149  * * Using `controller as` makes it obvious which controller you are accessing in the template when
21150  * multiple controllers apply to an element.
21151  * * If you are writing your controllers as classes you have easier access to the properties and
21152  * methods, which will appear on the scope, from inside the controller code.
21153  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
21154  * inheritance masking primitives.
21155  *
21156  * This example demonstrates the `controller as` syntax.
21157  *
21158  * <example name="ngControllerAs" module="controllerAsExample">
21159  *   <file name="index.html">
21160  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
21161  *      Name: <input type="text" ng-model="settings.name"/>
21162  *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
21163  *      Contact:
21164  *      <ul>
21165  *        <li ng-repeat="contact in settings.contacts">
21166  *          <select ng-model="contact.type">
21167  *             <option>phone</option>
21168  *             <option>email</option>
21169  *          </select>
21170  *          <input type="text" ng-model="contact.value"/>
21171  *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
21172  *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
21173  *        </li>
21174  *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
21175  *     </ul>
21176  *    </div>
21177  *   </file>
21178  *   <file name="app.js">
21179  *    angular.module('controllerAsExample', [])
21180  *      .controller('SettingsController1', SettingsController1);
21181  *
21182  *    function SettingsController1() {
21183  *      this.name = "John Smith";
21184  *      this.contacts = [
21185  *        {type: 'phone', value: '408 555 1212'},
21186  *        {type: 'email', value: 'john.smith@example.org'} ];
21187  *    }
21188  *
21189  *    SettingsController1.prototype.greet = function() {
21190  *      alert(this.name);
21191  *    };
21192  *
21193  *    SettingsController1.prototype.addContact = function() {
21194  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
21195  *    };
21196  *
21197  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
21198  *     var index = this.contacts.indexOf(contactToRemove);
21199  *      this.contacts.splice(index, 1);
21200  *    };
21201  *
21202  *    SettingsController1.prototype.clearContact = function(contact) {
21203  *      contact.type = 'phone';
21204  *      contact.value = '';
21205  *    };
21206  *   </file>
21207  *   <file name="protractor.js" type="protractor">
21208  *     it('should check controller as', function() {
21209  *       var container = element(by.id('ctrl-as-exmpl'));
21210  *         expect(container.element(by.model('settings.name'))
21211  *           .getAttribute('value')).toBe('John Smith');
21212  *
21213  *       var firstRepeat =
21214  *           container.element(by.repeater('contact in settings.contacts').row(0));
21215  *       var secondRepeat =
21216  *           container.element(by.repeater('contact in settings.contacts').row(1));
21217  *
21218  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21219  *           .toBe('408 555 1212');
21220  *
21221  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21222  *           .toBe('john.smith@example.org');
21223  *
21224  *       firstRepeat.element(by.linkText('clear')).click();
21225  *
21226  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21227  *           .toBe('');
21228  *
21229  *       container.element(by.linkText('add')).click();
21230  *
21231  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
21232  *           .element(by.model('contact.value'))
21233  *           .getAttribute('value'))
21234  *           .toBe('yourname@example.org');
21235  *     });
21236  *   </file>
21237  * </example>
21238  *
21239  * This example demonstrates the "attach to `$scope`" style of controller.
21240  *
21241  * <example name="ngController" module="controllerExample">
21242  *  <file name="index.html">
21243  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
21244  *     Name: <input type="text" ng-model="name"/>
21245  *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
21246  *     Contact:
21247  *     <ul>
21248  *       <li ng-repeat="contact in contacts">
21249  *         <select ng-model="contact.type">
21250  *            <option>phone</option>
21251  *            <option>email</option>
21252  *         </select>
21253  *         <input type="text" ng-model="contact.value"/>
21254  *         [ <a href="" ng-click="clearContact(contact)">clear</a>
21255  *         | <a href="" ng-click="removeContact(contact)">X</a> ]
21256  *       </li>
21257  *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
21258  *    </ul>
21259  *   </div>
21260  *  </file>
21261  *  <file name="app.js">
21262  *   angular.module('controllerExample', [])
21263  *     .controller('SettingsController2', ['$scope', SettingsController2]);
21264  *
21265  *   function SettingsController2($scope) {
21266  *     $scope.name = "John Smith";
21267  *     $scope.contacts = [
21268  *       {type:'phone', value:'408 555 1212'},
21269  *       {type:'email', value:'john.smith@example.org'} ];
21270  *
21271  *     $scope.greet = function() {
21272  *       alert($scope.name);
21273  *     };
21274  *
21275  *     $scope.addContact = function() {
21276  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
21277  *     };
21278  *
21279  *     $scope.removeContact = function(contactToRemove) {
21280  *       var index = $scope.contacts.indexOf(contactToRemove);
21281  *       $scope.contacts.splice(index, 1);
21282  *     };
21283  *
21284  *     $scope.clearContact = function(contact) {
21285  *       contact.type = 'phone';
21286  *       contact.value = '';
21287  *     };
21288  *   }
21289  *  </file>
21290  *  <file name="protractor.js" type="protractor">
21291  *    it('should check controller', function() {
21292  *      var container = element(by.id('ctrl-exmpl'));
21293  *
21294  *      expect(container.element(by.model('name'))
21295  *          .getAttribute('value')).toBe('John Smith');
21296  *
21297  *      var firstRepeat =
21298  *          container.element(by.repeater('contact in contacts').row(0));
21299  *      var secondRepeat =
21300  *          container.element(by.repeater('contact in contacts').row(1));
21301  *
21302  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21303  *          .toBe('408 555 1212');
21304  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21305  *          .toBe('john.smith@example.org');
21306  *
21307  *      firstRepeat.element(by.linkText('clear')).click();
21308  *
21309  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21310  *          .toBe('');
21311  *
21312  *      container.element(by.linkText('add')).click();
21313  *
21314  *      expect(container.element(by.repeater('contact in contacts').row(2))
21315  *          .element(by.model('contact.value'))
21316  *          .getAttribute('value'))
21317  *          .toBe('yourname@example.org');
21318  *    });
21319  *  </file>
21320  *</example>
21321
21322  */
21323 var ngControllerDirective = [function() {
21324   return {
21325     restrict: 'A',
21326     scope: true,
21327     controller: '@',
21328     priority: 500
21329   };
21330 }];
21331
21332 /**
21333  * @ngdoc directive
21334  * @name ngCsp
21335  *
21336  * @element html
21337  * @description
21338  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
21339  *
21340  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
21341  *
21342  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
21343  * For Angular to be CSP compatible there are only two things that we need to do differently:
21344  *
21345  * - don't use `Function` constructor to generate optimized value getters
21346  * - don't inject custom stylesheet into the document
21347  *
21348  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
21349  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
21350  * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
21351  * be raised.
21352  *
21353  * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
21354  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
21355  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
21356  *
21357  * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
21358  * autodetection however triggers a CSP error to be logged in the console:
21359  *
21360  * ```
21361  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
21362  * script in the following Content Security Policy directive: "default-src 'self'". Note that
21363  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
21364  * ```
21365  *
21366  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
21367  * directive on the root element of the application or on the `angular.js` script tag, whichever
21368  * appears first in the html document.
21369  *
21370  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
21371  *
21372  * @example
21373  * This example shows how to apply the `ngCsp` directive to the `html` tag.
21374    ```html
21375      <!doctype html>
21376      <html ng-app ng-csp>
21377      ...
21378      ...
21379      </html>
21380    ```
21381   * @example
21382       // Note: the suffix `.csp` in the example name triggers
21383       // csp mode in our http server!
21384       <example name="example.csp" module="cspExample" ng-csp="true">
21385         <file name="index.html">
21386           <div ng-controller="MainController as ctrl">
21387             <div>
21388               <button ng-click="ctrl.inc()" id="inc">Increment</button>
21389               <span id="counter">
21390                 {{ctrl.counter}}
21391               </span>
21392             </div>
21393
21394             <div>
21395               <button ng-click="ctrl.evil()" id="evil">Evil</button>
21396               <span id="evilError">
21397                 {{ctrl.evilError}}
21398               </span>
21399             </div>
21400           </div>
21401         </file>
21402         <file name="script.js">
21403            angular.module('cspExample', [])
21404              .controller('MainController', function() {
21405                 this.counter = 0;
21406                 this.inc = function() {
21407                   this.counter++;
21408                 };
21409                 this.evil = function() {
21410                   // jshint evil:true
21411                   try {
21412                     eval('1+2');
21413                   } catch (e) {
21414                     this.evilError = e.message;
21415                   }
21416                 };
21417               });
21418         </file>
21419         <file name="protractor.js" type="protractor">
21420           var util, webdriver;
21421
21422           var incBtn = element(by.id('inc'));
21423           var counter = element(by.id('counter'));
21424           var evilBtn = element(by.id('evil'));
21425           var evilError = element(by.id('evilError'));
21426
21427           function getAndClearSevereErrors() {
21428             return browser.manage().logs().get('browser').then(function(browserLog) {
21429               return browserLog.filter(function(logEntry) {
21430                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
21431               });
21432             });
21433           }
21434
21435           function clearErrors() {
21436             getAndClearSevereErrors();
21437           }
21438
21439           function expectNoErrors() {
21440             getAndClearSevereErrors().then(function(filteredLog) {
21441               expect(filteredLog.length).toEqual(0);
21442               if (filteredLog.length) {
21443                 console.log('browser console errors: ' + util.inspect(filteredLog));
21444               }
21445             });
21446           }
21447
21448           function expectError(regex) {
21449             getAndClearSevereErrors().then(function(filteredLog) {
21450               var found = false;
21451               filteredLog.forEach(function(log) {
21452                 if (log.message.match(regex)) {
21453                   found = true;
21454                 }
21455               });
21456               if (!found) {
21457                 throw new Error('expected an error that matches ' + regex);
21458               }
21459             });
21460           }
21461
21462           beforeEach(function() {
21463             util = require('util');
21464             webdriver = require('protractor/node_modules/selenium-webdriver');
21465           });
21466
21467           // For now, we only test on Chrome,
21468           // as Safari does not load the page with Protractor's injected scripts,
21469           // and Firefox webdriver always disables content security policy (#6358)
21470           if (browser.params.browser !== 'chrome') {
21471             return;
21472           }
21473
21474           it('should not report errors when the page is loaded', function() {
21475             // clear errors so we are not dependent on previous tests
21476             clearErrors();
21477             // Need to reload the page as the page is already loaded when
21478             // we come here
21479             browser.driver.getCurrentUrl().then(function(url) {
21480               browser.get(url);
21481             });
21482             expectNoErrors();
21483           });
21484
21485           it('should evaluate expressions', function() {
21486             expect(counter.getText()).toEqual('0');
21487             incBtn.click();
21488             expect(counter.getText()).toEqual('1');
21489             expectNoErrors();
21490           });
21491
21492           it('should throw and report an error when using "eval"', function() {
21493             evilBtn.click();
21494             expect(evilError.getText()).toMatch(/Content Security Policy/);
21495             expectError(/Content Security Policy/);
21496           });
21497         </file>
21498       </example>
21499   */
21500
21501 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
21502 // bootstrap the system (before $parse is instantiated), for this reason we just have
21503 // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
21504
21505 /**
21506  * @ngdoc directive
21507  * @name ngClick
21508  *
21509  * @description
21510  * The ngClick directive allows you to specify custom behavior when
21511  * an element is clicked.
21512  *
21513  * @element ANY
21514  * @priority 0
21515  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
21516  * click. ({@link guide/expression#-event- Event object is available as `$event`})
21517  *
21518  * @example
21519    <example>
21520      <file name="index.html">
21521       <button ng-click="count = count + 1" ng-init="count=0">
21522         Increment
21523       </button>
21524       <span>
21525         count: {{count}}
21526       </span>
21527      </file>
21528      <file name="protractor.js" type="protractor">
21529        it('should check ng-click', function() {
21530          expect(element(by.binding('count')).getText()).toMatch('0');
21531          element(by.css('button')).click();
21532          expect(element(by.binding('count')).getText()).toMatch('1');
21533        });
21534      </file>
21535    </example>
21536  */
21537 /*
21538  * A collection of directives that allows creation of custom event handlers that are defined as
21539  * angular expressions and are compiled and executed within the current scope.
21540  */
21541 var ngEventDirectives = {};
21542
21543 // For events that might fire synchronously during DOM manipulation
21544 // we need to execute their event handlers asynchronously using $evalAsync,
21545 // so that they are not executed in an inconsistent state.
21546 var forceAsyncEvents = {
21547   'blur': true,
21548   'focus': true
21549 };
21550 forEach(
21551   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
21552   function(eventName) {
21553     var directiveName = directiveNormalize('ng-' + eventName);
21554     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
21555       return {
21556         restrict: 'A',
21557         compile: function($element, attr) {
21558           // We expose the powerful $event object on the scope that provides access to the Window,
21559           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
21560           // checks at the cost of speed since event handler expressions are not executed as
21561           // frequently as regular change detection.
21562           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
21563           return function ngEventHandler(scope, element) {
21564             element.on(eventName, function(event) {
21565               var callback = function() {
21566                 fn(scope, {$event:event});
21567               };
21568               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
21569                 scope.$evalAsync(callback);
21570               } else {
21571                 scope.$apply(callback);
21572               }
21573             });
21574           };
21575         }
21576       };
21577     }];
21578   }
21579 );
21580
21581 /**
21582  * @ngdoc directive
21583  * @name ngDblclick
21584  *
21585  * @description
21586  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
21587  *
21588  * @element ANY
21589  * @priority 0
21590  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
21591  * a dblclick. (The Event object is available as `$event`)
21592  *
21593  * @example
21594    <example>
21595      <file name="index.html">
21596       <button ng-dblclick="count = count + 1" ng-init="count=0">
21597         Increment (on double click)
21598       </button>
21599       count: {{count}}
21600      </file>
21601    </example>
21602  */
21603
21604
21605 /**
21606  * @ngdoc directive
21607  * @name ngMousedown
21608  *
21609  * @description
21610  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
21611  *
21612  * @element ANY
21613  * @priority 0
21614  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
21615  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
21616  *
21617  * @example
21618    <example>
21619      <file name="index.html">
21620       <button ng-mousedown="count = count + 1" ng-init="count=0">
21621         Increment (on mouse down)
21622       </button>
21623       count: {{count}}
21624      </file>
21625    </example>
21626  */
21627
21628
21629 /**
21630  * @ngdoc directive
21631  * @name ngMouseup
21632  *
21633  * @description
21634  * Specify custom behavior on mouseup event.
21635  *
21636  * @element ANY
21637  * @priority 0
21638  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
21639  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
21640  *
21641  * @example
21642    <example>
21643      <file name="index.html">
21644       <button ng-mouseup="count = count + 1" ng-init="count=0">
21645         Increment (on mouse up)
21646       </button>
21647       count: {{count}}
21648      </file>
21649    </example>
21650  */
21651
21652 /**
21653  * @ngdoc directive
21654  * @name ngMouseover
21655  *
21656  * @description
21657  * Specify custom behavior on mouseover event.
21658  *
21659  * @element ANY
21660  * @priority 0
21661  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
21662  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
21663  *
21664  * @example
21665    <example>
21666      <file name="index.html">
21667       <button ng-mouseover="count = count + 1" ng-init="count=0">
21668         Increment (when mouse is over)
21669       </button>
21670       count: {{count}}
21671      </file>
21672    </example>
21673  */
21674
21675
21676 /**
21677  * @ngdoc directive
21678  * @name ngMouseenter
21679  *
21680  * @description
21681  * Specify custom behavior on mouseenter event.
21682  *
21683  * @element ANY
21684  * @priority 0
21685  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
21686  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
21687  *
21688  * @example
21689    <example>
21690      <file name="index.html">
21691       <button ng-mouseenter="count = count + 1" ng-init="count=0">
21692         Increment (when mouse enters)
21693       </button>
21694       count: {{count}}
21695      </file>
21696    </example>
21697  */
21698
21699
21700 /**
21701  * @ngdoc directive
21702  * @name ngMouseleave
21703  *
21704  * @description
21705  * Specify custom behavior on mouseleave event.
21706  *
21707  * @element ANY
21708  * @priority 0
21709  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
21710  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
21711  *
21712  * @example
21713    <example>
21714      <file name="index.html">
21715       <button ng-mouseleave="count = count + 1" ng-init="count=0">
21716         Increment (when mouse leaves)
21717       </button>
21718       count: {{count}}
21719      </file>
21720    </example>
21721  */
21722
21723
21724 /**
21725  * @ngdoc directive
21726  * @name ngMousemove
21727  *
21728  * @description
21729  * Specify custom behavior on mousemove event.
21730  *
21731  * @element ANY
21732  * @priority 0
21733  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
21734  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
21735  *
21736  * @example
21737    <example>
21738      <file name="index.html">
21739       <button ng-mousemove="count = count + 1" ng-init="count=0">
21740         Increment (when mouse moves)
21741       </button>
21742       count: {{count}}
21743      </file>
21744    </example>
21745  */
21746
21747
21748 /**
21749  * @ngdoc directive
21750  * @name ngKeydown
21751  *
21752  * @description
21753  * Specify custom behavior on keydown event.
21754  *
21755  * @element ANY
21756  * @priority 0
21757  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
21758  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21759  *
21760  * @example
21761    <example>
21762      <file name="index.html">
21763       <input ng-keydown="count = count + 1" ng-init="count=0">
21764       key down count: {{count}}
21765      </file>
21766    </example>
21767  */
21768
21769
21770 /**
21771  * @ngdoc directive
21772  * @name ngKeyup
21773  *
21774  * @description
21775  * Specify custom behavior on keyup event.
21776  *
21777  * @element ANY
21778  * @priority 0
21779  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
21780  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21781  *
21782  * @example
21783    <example>
21784      <file name="index.html">
21785        <p>Typing in the input box below updates the key count</p>
21786        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
21787
21788        <p>Typing in the input box below updates the keycode</p>
21789        <input ng-keyup="event=$event">
21790        <p>event keyCode: {{ event.keyCode }}</p>
21791        <p>event altKey: {{ event.altKey }}</p>
21792      </file>
21793    </example>
21794  */
21795
21796
21797 /**
21798  * @ngdoc directive
21799  * @name ngKeypress
21800  *
21801  * @description
21802  * Specify custom behavior on keypress event.
21803  *
21804  * @element ANY
21805  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
21806  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
21807  * and can be interrogated for keyCode, altKey, etc.)
21808  *
21809  * @example
21810    <example>
21811      <file name="index.html">
21812       <input ng-keypress="count = count + 1" ng-init="count=0">
21813       key press count: {{count}}
21814      </file>
21815    </example>
21816  */
21817
21818
21819 /**
21820  * @ngdoc directive
21821  * @name ngSubmit
21822  *
21823  * @description
21824  * Enables binding angular expressions to onsubmit events.
21825  *
21826  * Additionally it prevents the default action (which for form means sending the request to the
21827  * server and reloading the current page), but only if the form does not contain `action`,
21828  * `data-action`, or `x-action` attributes.
21829  *
21830  * <div class="alert alert-warning">
21831  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
21832  * `ngSubmit` handlers together. See the
21833  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
21834  * for a detailed discussion of when `ngSubmit` may be triggered.
21835  * </div>
21836  *
21837  * @element form
21838  * @priority 0
21839  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
21840  * ({@link guide/expression#-event- Event object is available as `$event`})
21841  *
21842  * @example
21843    <example module="submitExample">
21844      <file name="index.html">
21845       <script>
21846         angular.module('submitExample', [])
21847           .controller('ExampleController', ['$scope', function($scope) {
21848             $scope.list = [];
21849             $scope.text = 'hello';
21850             $scope.submit = function() {
21851               if ($scope.text) {
21852                 $scope.list.push(this.text);
21853                 $scope.text = '';
21854               }
21855             };
21856           }]);
21857       </script>
21858       <form ng-submit="submit()" ng-controller="ExampleController">
21859         Enter text and hit enter:
21860         <input type="text" ng-model="text" name="text" />
21861         <input type="submit" id="submit" value="Submit" />
21862         <pre>list={{list}}</pre>
21863       </form>
21864      </file>
21865      <file name="protractor.js" type="protractor">
21866        it('should check ng-submit', function() {
21867          expect(element(by.binding('list')).getText()).toBe('list=[]');
21868          element(by.css('#submit')).click();
21869          expect(element(by.binding('list')).getText()).toContain('hello');
21870          expect(element(by.model('text')).getAttribute('value')).toBe('');
21871        });
21872        it('should ignore empty strings', function() {
21873          expect(element(by.binding('list')).getText()).toBe('list=[]');
21874          element(by.css('#submit')).click();
21875          element(by.css('#submit')).click();
21876          expect(element(by.binding('list')).getText()).toContain('hello');
21877         });
21878      </file>
21879    </example>
21880  */
21881
21882 /**
21883  * @ngdoc directive
21884  * @name ngFocus
21885  *
21886  * @description
21887  * Specify custom behavior on focus event.
21888  *
21889  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
21890  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
21891  * during an `$apply` to ensure a consistent state.
21892  *
21893  * @element window, input, select, textarea, a
21894  * @priority 0
21895  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
21896  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
21897  *
21898  * @example
21899  * See {@link ng.directive:ngClick ngClick}
21900  */
21901
21902 /**
21903  * @ngdoc directive
21904  * @name ngBlur
21905  *
21906  * @description
21907  * Specify custom behavior on blur event.
21908  *
21909  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
21910  * an element has lost focus.
21911  *
21912  * Note: As the `blur` event is executed synchronously also during DOM manipulations
21913  * (e.g. removing a focussed input),
21914  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
21915  * during an `$apply` to ensure a consistent state.
21916  *
21917  * @element window, input, select, textarea, a
21918  * @priority 0
21919  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
21920  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
21921  *
21922  * @example
21923  * See {@link ng.directive:ngClick ngClick}
21924  */
21925
21926 /**
21927  * @ngdoc directive
21928  * @name ngCopy
21929  *
21930  * @description
21931  * Specify custom behavior on copy event.
21932  *
21933  * @element window, input, select, textarea, a
21934  * @priority 0
21935  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
21936  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
21937  *
21938  * @example
21939    <example>
21940      <file name="index.html">
21941       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
21942       copied: {{copied}}
21943      </file>
21944    </example>
21945  */
21946
21947 /**
21948  * @ngdoc directive
21949  * @name ngCut
21950  *
21951  * @description
21952  * Specify custom behavior on cut event.
21953  *
21954  * @element window, input, select, textarea, a
21955  * @priority 0
21956  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
21957  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
21958  *
21959  * @example
21960    <example>
21961      <file name="index.html">
21962       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
21963       cut: {{cut}}
21964      </file>
21965    </example>
21966  */
21967
21968 /**
21969  * @ngdoc directive
21970  * @name ngPaste
21971  *
21972  * @description
21973  * Specify custom behavior on paste event.
21974  *
21975  * @element window, input, select, textarea, a
21976  * @priority 0
21977  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
21978  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
21979  *
21980  * @example
21981    <example>
21982      <file name="index.html">
21983       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
21984       pasted: {{paste}}
21985      </file>
21986    </example>
21987  */
21988
21989 /**
21990  * @ngdoc directive
21991  * @name ngIf
21992  * @restrict A
21993  *
21994  * @description
21995  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
21996  * {expression}. If the expression assigned to `ngIf` evaluates to a false
21997  * value then the element is removed from the DOM, otherwise a clone of the
21998  * element is reinserted into the DOM.
21999  *
22000  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
22001  * element in the DOM rather than changing its visibility via the `display` css property.  A common
22002  * case when this difference is significant is when using css selectors that rely on an element's
22003  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
22004  *
22005  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
22006  * is created when the element is restored.  The scope created within `ngIf` inherits from
22007  * its parent scope using
22008  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
22009  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
22010  * a javascript primitive defined in the parent scope. In this case any modifications made to the
22011  * variable within the child scope will override (hide) the value in the parent scope.
22012  *
22013  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
22014  * is if an element's class attribute is directly modified after it's compiled, using something like
22015  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
22016  * the added class will be lost because the original compiled state is used to regenerate the element.
22017  *
22018  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
22019  * and `leave` effects.
22020  *
22021  * @animations
22022  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
22023  * leave - happens just before the `ngIf` contents are removed from the DOM
22024  *
22025  * @element ANY
22026  * @scope
22027  * @priority 600
22028  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
22029  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
22030  *     element is added to the DOM tree.
22031  *
22032  * @example
22033   <example module="ngAnimate" deps="angular-animate.js" animations="true">
22034     <file name="index.html">
22035       Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
22036       Show when checked:
22037       <span ng-if="checked" class="animate-if">
22038         This is removed when the checkbox is unchecked.
22039       </span>
22040     </file>
22041     <file name="animations.css">
22042       .animate-if {
22043         background:white;
22044         border:1px solid black;
22045         padding:10px;
22046       }
22047
22048       .animate-if.ng-enter, .animate-if.ng-leave {
22049         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22050         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22051       }
22052
22053       .animate-if.ng-enter,
22054       .animate-if.ng-leave.ng-leave-active {
22055         opacity:0;
22056       }
22057
22058       .animate-if.ng-leave,
22059       .animate-if.ng-enter.ng-enter-active {
22060         opacity:1;
22061       }
22062     </file>
22063   </example>
22064  */
22065 var ngIfDirective = ['$animate', function($animate) {
22066   return {
22067     multiElement: true,
22068     transclude: 'element',
22069     priority: 600,
22070     terminal: true,
22071     restrict: 'A',
22072     $$tlb: true,
22073     link: function($scope, $element, $attr, ctrl, $transclude) {
22074         var block, childScope, previousElements;
22075         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
22076
22077           if (value) {
22078             if (!childScope) {
22079               $transclude(function(clone, newScope) {
22080                 childScope = newScope;
22081                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
22082                 // Note: We only need the first/last node of the cloned nodes.
22083                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
22084                 // by a directive with templateUrl when its template arrives.
22085                 block = {
22086                   clone: clone
22087                 };
22088                 $animate.enter(clone, $element.parent(), $element);
22089               });
22090             }
22091           } else {
22092             if (previousElements) {
22093               previousElements.remove();
22094               previousElements = null;
22095             }
22096             if (childScope) {
22097               childScope.$destroy();
22098               childScope = null;
22099             }
22100             if (block) {
22101               previousElements = getBlockNodes(block.clone);
22102               $animate.leave(previousElements).then(function() {
22103                 previousElements = null;
22104               });
22105               block = null;
22106             }
22107           }
22108         });
22109     }
22110   };
22111 }];
22112
22113 /**
22114  * @ngdoc directive
22115  * @name ngInclude
22116  * @restrict ECA
22117  *
22118  * @description
22119  * Fetches, compiles and includes an external HTML fragment.
22120  *
22121  * By default, the template URL is restricted to the same domain and protocol as the
22122  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
22123  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
22124  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
22125  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
22126  * ng.$sce Strict Contextual Escaping}.
22127  *
22128  * In addition, the browser's
22129  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
22130  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
22131  * policy may further restrict whether the template is successfully loaded.
22132  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
22133  * access on some browsers.
22134  *
22135  * @animations
22136  * enter - animation is used to bring new content into the browser.
22137  * leave - animation is used to animate existing content away.
22138  *
22139  * The enter and leave animation occur concurrently.
22140  *
22141  * @scope
22142  * @priority 400
22143  *
22144  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
22145  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
22146  * @param {string=} onload Expression to evaluate when a new partial is loaded.
22147  *
22148  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
22149  *                  $anchorScroll} to scroll the viewport after the content is loaded.
22150  *
22151  *                  - If the attribute is not set, disable scrolling.
22152  *                  - If the attribute is set without value, enable scrolling.
22153  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
22154  *
22155  * @example
22156   <example module="includeExample" deps="angular-animate.js" animations="true">
22157     <file name="index.html">
22158      <div ng-controller="ExampleController">
22159        <select ng-model="template" ng-options="t.name for t in templates">
22160         <option value="">(blank)</option>
22161        </select>
22162        url of the template: <code>{{template.url}}</code>
22163        <hr/>
22164        <div class="slide-animate-container">
22165          <div class="slide-animate" ng-include="template.url"></div>
22166        </div>
22167      </div>
22168     </file>
22169     <file name="script.js">
22170       angular.module('includeExample', ['ngAnimate'])
22171         .controller('ExampleController', ['$scope', function($scope) {
22172           $scope.templates =
22173             [ { name: 'template1.html', url: 'template1.html'},
22174               { name: 'template2.html', url: 'template2.html'} ];
22175           $scope.template = $scope.templates[0];
22176         }]);
22177      </file>
22178     <file name="template1.html">
22179       Content of template1.html
22180     </file>
22181     <file name="template2.html">
22182       Content of template2.html
22183     </file>
22184     <file name="animations.css">
22185       .slide-animate-container {
22186         position:relative;
22187         background:white;
22188         border:1px solid black;
22189         height:40px;
22190         overflow:hidden;
22191       }
22192
22193       .slide-animate {
22194         padding:10px;
22195       }
22196
22197       .slide-animate.ng-enter, .slide-animate.ng-leave {
22198         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22199         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22200
22201         position:absolute;
22202         top:0;
22203         left:0;
22204         right:0;
22205         bottom:0;
22206         display:block;
22207         padding:10px;
22208       }
22209
22210       .slide-animate.ng-enter {
22211         top:-50px;
22212       }
22213       .slide-animate.ng-enter.ng-enter-active {
22214         top:0;
22215       }
22216
22217       .slide-animate.ng-leave {
22218         top:0;
22219       }
22220       .slide-animate.ng-leave.ng-leave-active {
22221         top:50px;
22222       }
22223     </file>
22224     <file name="protractor.js" type="protractor">
22225       var templateSelect = element(by.model('template'));
22226       var includeElem = element(by.css('[ng-include]'));
22227
22228       it('should load template1.html', function() {
22229         expect(includeElem.getText()).toMatch(/Content of template1.html/);
22230       });
22231
22232       it('should load template2.html', function() {
22233         if (browser.params.browser == 'firefox') {
22234           // Firefox can't handle using selects
22235           // See https://github.com/angular/protractor/issues/480
22236           return;
22237         }
22238         templateSelect.click();
22239         templateSelect.all(by.css('option')).get(2).click();
22240         expect(includeElem.getText()).toMatch(/Content of template2.html/);
22241       });
22242
22243       it('should change to blank', function() {
22244         if (browser.params.browser == 'firefox') {
22245           // Firefox can't handle using selects
22246           return;
22247         }
22248         templateSelect.click();
22249         templateSelect.all(by.css('option')).get(0).click();
22250         expect(includeElem.isPresent()).toBe(false);
22251       });
22252     </file>
22253   </example>
22254  */
22255
22256
22257 /**
22258  * @ngdoc event
22259  * @name ngInclude#$includeContentRequested
22260  * @eventType emit on the scope ngInclude was declared in
22261  * @description
22262  * Emitted every time the ngInclude content is requested.
22263  *
22264  * @param {Object} angularEvent Synthetic event object.
22265  * @param {String} src URL of content to load.
22266  */
22267
22268
22269 /**
22270  * @ngdoc event
22271  * @name ngInclude#$includeContentLoaded
22272  * @eventType emit on the current ngInclude scope
22273  * @description
22274  * Emitted every time the ngInclude content is reloaded.
22275  *
22276  * @param {Object} angularEvent Synthetic event object.
22277  * @param {String} src URL of content to load.
22278  */
22279
22280
22281 /**
22282  * @ngdoc event
22283  * @name ngInclude#$includeContentError
22284  * @eventType emit on the scope ngInclude was declared in
22285  * @description
22286  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
22287  *
22288  * @param {Object} angularEvent Synthetic event object.
22289  * @param {String} src URL of content to load.
22290  */
22291 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
22292                   function($templateRequest,   $anchorScroll,   $animate,   $sce) {
22293   return {
22294     restrict: 'ECA',
22295     priority: 400,
22296     terminal: true,
22297     transclude: 'element',
22298     controller: angular.noop,
22299     compile: function(element, attr) {
22300       var srcExp = attr.ngInclude || attr.src,
22301           onloadExp = attr.onload || '',
22302           autoScrollExp = attr.autoscroll;
22303
22304       return function(scope, $element, $attr, ctrl, $transclude) {
22305         var changeCounter = 0,
22306             currentScope,
22307             previousElement,
22308             currentElement;
22309
22310         var cleanupLastIncludeContent = function() {
22311           if (previousElement) {
22312             previousElement.remove();
22313             previousElement = null;
22314           }
22315           if (currentScope) {
22316             currentScope.$destroy();
22317             currentScope = null;
22318           }
22319           if (currentElement) {
22320             $animate.leave(currentElement).then(function() {
22321               previousElement = null;
22322             });
22323             previousElement = currentElement;
22324             currentElement = null;
22325           }
22326         };
22327
22328         scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
22329           var afterAnimation = function() {
22330             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
22331               $anchorScroll();
22332             }
22333           };
22334           var thisChangeId = ++changeCounter;
22335
22336           if (src) {
22337             //set the 2nd param to true to ignore the template request error so that the inner
22338             //contents and scope can be cleaned up.
22339             $templateRequest(src, true).then(function(response) {
22340               if (thisChangeId !== changeCounter) return;
22341               var newScope = scope.$new();
22342               ctrl.template = response;
22343
22344               // Note: This will also link all children of ng-include that were contained in the original
22345               // html. If that content contains controllers, ... they could pollute/change the scope.
22346               // However, using ng-include on an element with additional content does not make sense...
22347               // Note: We can't remove them in the cloneAttchFn of $transclude as that
22348               // function is called before linking the content, which would apply child
22349               // directives to non existing elements.
22350               var clone = $transclude(newScope, function(clone) {
22351                 cleanupLastIncludeContent();
22352                 $animate.enter(clone, null, $element).then(afterAnimation);
22353               });
22354
22355               currentScope = newScope;
22356               currentElement = clone;
22357
22358               currentScope.$emit('$includeContentLoaded', src);
22359               scope.$eval(onloadExp);
22360             }, function() {
22361               if (thisChangeId === changeCounter) {
22362                 cleanupLastIncludeContent();
22363                 scope.$emit('$includeContentError', src);
22364               }
22365             });
22366             scope.$emit('$includeContentRequested', src);
22367           } else {
22368             cleanupLastIncludeContent();
22369             ctrl.template = null;
22370           }
22371         });
22372       };
22373     }
22374   };
22375 }];
22376
22377 // This directive is called during the $transclude call of the first `ngInclude` directive.
22378 // It will replace and compile the content of the element with the loaded template.
22379 // We need this directive so that the element content is already filled when
22380 // the link function of another directive on the same element as ngInclude
22381 // is called.
22382 var ngIncludeFillContentDirective = ['$compile',
22383   function($compile) {
22384     return {
22385       restrict: 'ECA',
22386       priority: -400,
22387       require: 'ngInclude',
22388       link: function(scope, $element, $attr, ctrl) {
22389         if (/SVG/.test($element[0].toString())) {
22390           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
22391           // support innerHTML, so detect this here and try to generate the contents
22392           // specially.
22393           $element.empty();
22394           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
22395               function namespaceAdaptedClone(clone) {
22396             $element.append(clone);
22397           }, {futureParentElement: $element});
22398           return;
22399         }
22400
22401         $element.html(ctrl.template);
22402         $compile($element.contents())(scope);
22403       }
22404     };
22405   }];
22406
22407 /**
22408  * @ngdoc directive
22409  * @name ngInit
22410  * @restrict AC
22411  *
22412  * @description
22413  * The `ngInit` directive allows you to evaluate an expression in the
22414  * current scope.
22415  *
22416  * <div class="alert alert-error">
22417  * The only appropriate use of `ngInit` is for aliasing special properties of
22418  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
22419  * should use {@link guide/controller controllers} rather than `ngInit`
22420  * to initialize values on a scope.
22421  * </div>
22422  * <div class="alert alert-warning">
22423  * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
22424  * sure you have parenthesis for correct precedence:
22425  * <pre class="prettyprint">
22426  * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
22427  * </pre>
22428  * </div>
22429  *
22430  * @priority 450
22431  *
22432  * @element ANY
22433  * @param {expression} ngInit {@link guide/expression Expression} to eval.
22434  *
22435  * @example
22436    <example module="initExample">
22437      <file name="index.html">
22438    <script>
22439      angular.module('initExample', [])
22440        .controller('ExampleController', ['$scope', function($scope) {
22441          $scope.list = [['a', 'b'], ['c', 'd']];
22442        }]);
22443    </script>
22444    <div ng-controller="ExampleController">
22445      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
22446        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
22447           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
22448        </div>
22449      </div>
22450    </div>
22451      </file>
22452      <file name="protractor.js" type="protractor">
22453        it('should alias index positions', function() {
22454          var elements = element.all(by.css('.example-init'));
22455          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
22456          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
22457          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
22458          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
22459        });
22460      </file>
22461    </example>
22462  */
22463 var ngInitDirective = ngDirective({
22464   priority: 450,
22465   compile: function() {
22466     return {
22467       pre: function(scope, element, attrs) {
22468         scope.$eval(attrs.ngInit);
22469       }
22470     };
22471   }
22472 });
22473
22474 /**
22475  * @ngdoc directive
22476  * @name ngList
22477  *
22478  * @description
22479  * Text input that converts between a delimited string and an array of strings. The default
22480  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
22481  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
22482  *
22483  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
22484  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
22485  *   list item is respected. This implies that the user of the directive is responsible for
22486  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
22487  *   tab or newline character.
22488  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
22489  *   when joining the list items back together) and whitespace around each list item is stripped
22490  *   before it is added to the model.
22491  *
22492  * ### Example with Validation
22493  *
22494  * <example name="ngList-directive" module="listExample">
22495  *   <file name="app.js">
22496  *      angular.module('listExample', [])
22497  *        .controller('ExampleController', ['$scope', function($scope) {
22498  *          $scope.names = ['morpheus', 'neo', 'trinity'];
22499  *        }]);
22500  *   </file>
22501  *   <file name="index.html">
22502  *    <form name="myForm" ng-controller="ExampleController">
22503  *      List: <input name="namesInput" ng-model="names" ng-list required>
22504  *      <span class="error" ng-show="myForm.namesInput.$error.required">
22505  *        Required!</span>
22506  *      <br>
22507  *      <tt>names = {{names}}</tt><br/>
22508  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
22509  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
22510  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22511  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22512  *     </form>
22513  *   </file>
22514  *   <file name="protractor.js" type="protractor">
22515  *     var listInput = element(by.model('names'));
22516  *     var names = element(by.exactBinding('names'));
22517  *     var valid = element(by.binding('myForm.namesInput.$valid'));
22518  *     var error = element(by.css('span.error'));
22519  *
22520  *     it('should initialize to model', function() {
22521  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
22522  *       expect(valid.getText()).toContain('true');
22523  *       expect(error.getCssValue('display')).toBe('none');
22524  *     });
22525  *
22526  *     it('should be invalid if empty', function() {
22527  *       listInput.clear();
22528  *       listInput.sendKeys('');
22529  *
22530  *       expect(names.getText()).toContain('');
22531  *       expect(valid.getText()).toContain('false');
22532  *       expect(error.getCssValue('display')).not.toBe('none');
22533  *     });
22534  *   </file>
22535  * </example>
22536  *
22537  * ### Example - splitting on whitespace
22538  * <example name="ngList-directive-newlines">
22539  *   <file name="index.html">
22540  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
22541  *    <pre>{{ list | json }}</pre>
22542  *   </file>
22543  *   <file name="protractor.js" type="protractor">
22544  *     it("should split the text by newlines", function() {
22545  *       var listInput = element(by.model('list'));
22546  *       var output = element(by.binding('list | json'));
22547  *       listInput.sendKeys('abc\ndef\nghi');
22548  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
22549  *     });
22550  *   </file>
22551  * </example>
22552  *
22553  * @element input
22554  * @param {string=} ngList optional delimiter that should be used to split the value.
22555  */
22556 var ngListDirective = function() {
22557   return {
22558     restrict: 'A',
22559     priority: 100,
22560     require: 'ngModel',
22561     link: function(scope, element, attr, ctrl) {
22562       // We want to control whitespace trimming so we use this convoluted approach
22563       // to access the ngList attribute, which doesn't pre-trim the attribute
22564       var ngList = element.attr(attr.$attr.ngList) || ', ';
22565       var trimValues = attr.ngTrim !== 'false';
22566       var separator = trimValues ? trim(ngList) : ngList;
22567
22568       var parse = function(viewValue) {
22569         // If the viewValue is invalid (say required but empty) it will be `undefined`
22570         if (isUndefined(viewValue)) return;
22571
22572         var list = [];
22573
22574         if (viewValue) {
22575           forEach(viewValue.split(separator), function(value) {
22576             if (value) list.push(trimValues ? trim(value) : value);
22577           });
22578         }
22579
22580         return list;
22581       };
22582
22583       ctrl.$parsers.push(parse);
22584       ctrl.$formatters.push(function(value) {
22585         if (isArray(value)) {
22586           return value.join(ngList);
22587         }
22588
22589         return undefined;
22590       });
22591
22592       // Override the standard $isEmpty because an empty array means the input is empty.
22593       ctrl.$isEmpty = function(value) {
22594         return !value || !value.length;
22595       };
22596     }
22597   };
22598 };
22599
22600 /* global VALID_CLASS: true,
22601   INVALID_CLASS: true,
22602   PRISTINE_CLASS: true,
22603   DIRTY_CLASS: true,
22604   UNTOUCHED_CLASS: true,
22605   TOUCHED_CLASS: true,
22606 */
22607
22608 var VALID_CLASS = 'ng-valid',
22609     INVALID_CLASS = 'ng-invalid',
22610     PRISTINE_CLASS = 'ng-pristine',
22611     DIRTY_CLASS = 'ng-dirty',
22612     UNTOUCHED_CLASS = 'ng-untouched',
22613     TOUCHED_CLASS = 'ng-touched',
22614     PENDING_CLASS = 'ng-pending';
22615
22616
22617 var $ngModelMinErr = new minErr('ngModel');
22618
22619 /**
22620  * @ngdoc type
22621  * @name ngModel.NgModelController
22622  *
22623  * @property {string} $viewValue Actual string value in the view.
22624  * @property {*} $modelValue The value in the model that the control is bound to.
22625  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
22626        the control reads value from the DOM. The functions are called in array order, each passing
22627        its return value through to the next. The last return value is forwarded to the
22628        {@link ngModel.NgModelController#$validators `$validators`} collection.
22629
22630 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
22631 `$viewValue`}.
22632
22633 Returning `undefined` from a parser means a parse error occurred. In that case,
22634 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
22635 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
22636 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
22637
22638  *
22639  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
22640        the model value changes. The functions are called in reverse array order, each passing the value through to the
22641        next. The last return value is used as the actual DOM value.
22642        Used to format / convert values for display in the control.
22643  * ```js
22644  * function formatter(value) {
22645  *   if (value) {
22646  *     return value.toUpperCase();
22647  *   }
22648  * }
22649  * ngModel.$formatters.push(formatter);
22650  * ```
22651  *
22652  * @property {Object.<string, function>} $validators A collection of validators that are applied
22653  *      whenever the model value changes. The key value within the object refers to the name of the
22654  *      validator while the function refers to the validation operation. The validation operation is
22655  *      provided with the model value as an argument and must return a true or false value depending
22656  *      on the response of that validation.
22657  *
22658  * ```js
22659  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
22660  *   var value = modelValue || viewValue;
22661  *   return /[0-9]+/.test(value) &&
22662  *          /[a-z]+/.test(value) &&
22663  *          /[A-Z]+/.test(value) &&
22664  *          /\W+/.test(value);
22665  * };
22666  * ```
22667  *
22668  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
22669  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
22670  *      is expected to return a promise when it is run during the model validation process. Once the promise
22671  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
22672  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
22673  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
22674  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
22675  *      will only run once all synchronous validators have passed.
22676  *
22677  * Please note that if $http is used then it is important that the server returns a success HTTP response code
22678  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
22679  *
22680  * ```js
22681  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
22682  *   var value = modelValue || viewValue;
22683  *
22684  *   // Lookup user by username
22685  *   return $http.get('/api/users/' + value).
22686  *      then(function resolved() {
22687  *        //username exists, this means validation fails
22688  *        return $q.reject('exists');
22689  *      }, function rejected() {
22690  *        //username does not exist, therefore this validation passes
22691  *        return true;
22692  *      });
22693  * };
22694  * ```
22695  *
22696  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
22697  *     view value has changed. It is called with no arguments, and its return value is ignored.
22698  *     This can be used in place of additional $watches against the model value.
22699  *
22700  * @property {Object} $error An object hash with all failing validator ids as keys.
22701  * @property {Object} $pending An object hash with all pending validator ids as keys.
22702  *
22703  * @property {boolean} $untouched True if control has not lost focus yet.
22704  * @property {boolean} $touched True if control has lost focus.
22705  * @property {boolean} $pristine True if user has not interacted with the control yet.
22706  * @property {boolean} $dirty True if user has already interacted with the control.
22707  * @property {boolean} $valid True if there is no error.
22708  * @property {boolean} $invalid True if at least one error on the control.
22709  * @property {string} $name The name attribute of the control.
22710  *
22711  * @description
22712  *
22713  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
22714  * The controller contains services for data-binding, validation, CSS updates, and value formatting
22715  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
22716  * listening to DOM events.
22717  * Such DOM related logic should be provided by other directives which make use of
22718  * `NgModelController` for data-binding to control elements.
22719  * Angular provides this DOM logic for most {@link input `input`} elements.
22720  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
22721  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
22722  *
22723  * @example
22724  * ### Custom Control Example
22725  * This example shows how to use `NgModelController` with a custom control to achieve
22726  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
22727  * collaborate together to achieve the desired result.
22728  *
22729  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
22730  * contents be edited in place by the user.
22731  *
22732  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
22733  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
22734  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
22735  * that content using the `$sce` service.
22736  *
22737  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
22738     <file name="style.css">
22739       [contenteditable] {
22740         border: 1px solid black;
22741         background-color: white;
22742         min-height: 20px;
22743       }
22744
22745       .ng-invalid {
22746         border: 1px solid red;
22747       }
22748
22749     </file>
22750     <file name="script.js">
22751       angular.module('customControl', ['ngSanitize']).
22752         directive('contenteditable', ['$sce', function($sce) {
22753           return {
22754             restrict: 'A', // only activate on element attribute
22755             require: '?ngModel', // get a hold of NgModelController
22756             link: function(scope, element, attrs, ngModel) {
22757               if (!ngModel) return; // do nothing if no ng-model
22758
22759               // Specify how UI should be updated
22760               ngModel.$render = function() {
22761                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
22762               };
22763
22764               // Listen for change events to enable binding
22765               element.on('blur keyup change', function() {
22766                 scope.$evalAsync(read);
22767               });
22768               read(); // initialize
22769
22770               // Write data to the model
22771               function read() {
22772                 var html = element.html();
22773                 // When we clear the content editable the browser leaves a <br> behind
22774                 // If strip-br attribute is provided then we strip this out
22775                 if ( attrs.stripBr && html == '<br>' ) {
22776                   html = '';
22777                 }
22778                 ngModel.$setViewValue(html);
22779               }
22780             }
22781           };
22782         }]);
22783     </file>
22784     <file name="index.html">
22785       <form name="myForm">
22786        <div contenteditable
22787             name="myWidget" ng-model="userContent"
22788             strip-br="true"
22789             required>Change me!</div>
22790         <span ng-show="myForm.myWidget.$error.required">Required!</span>
22791        <hr>
22792        <textarea ng-model="userContent"></textarea>
22793       </form>
22794     </file>
22795     <file name="protractor.js" type="protractor">
22796     it('should data-bind and become invalid', function() {
22797       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
22798         // SafariDriver can't handle contenteditable
22799         // and Firefox driver can't clear contenteditables very well
22800         return;
22801       }
22802       var contentEditable = element(by.css('[contenteditable]'));
22803       var content = 'Change me!';
22804
22805       expect(contentEditable.getText()).toEqual(content);
22806
22807       contentEditable.clear();
22808       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
22809       expect(contentEditable.getText()).toEqual('');
22810       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
22811     });
22812     </file>
22813  * </example>
22814  *
22815  *
22816  */
22817 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
22818     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
22819   this.$viewValue = Number.NaN;
22820   this.$modelValue = Number.NaN;
22821   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
22822   this.$validators = {};
22823   this.$asyncValidators = {};
22824   this.$parsers = [];
22825   this.$formatters = [];
22826   this.$viewChangeListeners = [];
22827   this.$untouched = true;
22828   this.$touched = false;
22829   this.$pristine = true;
22830   this.$dirty = false;
22831   this.$valid = true;
22832   this.$invalid = false;
22833   this.$error = {}; // keep invalid keys here
22834   this.$$success = {}; // keep valid keys here
22835   this.$pending = undefined; // keep pending keys here
22836   this.$name = $interpolate($attr.name || '', false)($scope);
22837
22838
22839   var parsedNgModel = $parse($attr.ngModel),
22840       parsedNgModelAssign = parsedNgModel.assign,
22841       ngModelGet = parsedNgModel,
22842       ngModelSet = parsedNgModelAssign,
22843       pendingDebounce = null,
22844       parserValid,
22845       ctrl = this;
22846
22847   this.$$setOptions = function(options) {
22848     ctrl.$options = options;
22849     if (options && options.getterSetter) {
22850       var invokeModelGetter = $parse($attr.ngModel + '()'),
22851           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
22852
22853       ngModelGet = function($scope) {
22854         var modelValue = parsedNgModel($scope);
22855         if (isFunction(modelValue)) {
22856           modelValue = invokeModelGetter($scope);
22857         }
22858         return modelValue;
22859       };
22860       ngModelSet = function($scope, newValue) {
22861         if (isFunction(parsedNgModel($scope))) {
22862           invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
22863         } else {
22864           parsedNgModelAssign($scope, ctrl.$modelValue);
22865         }
22866       };
22867     } else if (!parsedNgModel.assign) {
22868       throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
22869           $attr.ngModel, startingTag($element));
22870     }
22871   };
22872
22873   /**
22874    * @ngdoc method
22875    * @name ngModel.NgModelController#$render
22876    *
22877    * @description
22878    * Called when the view needs to be updated. It is expected that the user of the ng-model
22879    * directive will implement this method.
22880    *
22881    * The `$render()` method is invoked in the following situations:
22882    *
22883    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
22884    *   committed value then `$render()` is called to update the input control.
22885    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
22886    *   the `$viewValue` are different to last time.
22887    *
22888    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
22889    * `$modelValue` and `$viewValue` are actually different to their previous value. If `$modelValue`
22890    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
22891    * invoked if you only change a property on the objects.
22892    */
22893   this.$render = noop;
22894
22895   /**
22896    * @ngdoc method
22897    * @name ngModel.NgModelController#$isEmpty
22898    *
22899    * @description
22900    * This is called when we need to determine if the value of an input is empty.
22901    *
22902    * For instance, the required directive does this to work out if the input has data or not.
22903    *
22904    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
22905    *
22906    * You can override this for input directives whose concept of being empty is different to the
22907    * default. The `checkboxInputType` directive does this because in its case a value of `false`
22908    * implies empty.
22909    *
22910    * @param {*} value The value of the input to check for emptiness.
22911    * @returns {boolean} True if `value` is "empty".
22912    */
22913   this.$isEmpty = function(value) {
22914     return isUndefined(value) || value === '' || value === null || value !== value;
22915   };
22916
22917   var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
22918       currentValidationRunId = 0;
22919
22920   /**
22921    * @ngdoc method
22922    * @name ngModel.NgModelController#$setValidity
22923    *
22924    * @description
22925    * Change the validity state, and notify the form.
22926    *
22927    * This method can be called within $parsers/$formatters or a custom validation implementation.
22928    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
22929    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
22930    *
22931    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
22932    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
22933    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
22934    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
22935    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
22936    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
22937    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
22938    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
22939    *                          Skipped is used by Angular when validators do not run because of parse errors and
22940    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
22941    */
22942   addSetValidityMethod({
22943     ctrl: this,
22944     $element: $element,
22945     set: function(object, property) {
22946       object[property] = true;
22947     },
22948     unset: function(object, property) {
22949       delete object[property];
22950     },
22951     parentForm: parentForm,
22952     $animate: $animate
22953   });
22954
22955   /**
22956    * @ngdoc method
22957    * @name ngModel.NgModelController#$setPristine
22958    *
22959    * @description
22960    * Sets the control to its pristine state.
22961    *
22962    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
22963    * state (`ng-pristine` class). A model is considered to be pristine when the control
22964    * has not been changed from when first compiled.
22965    */
22966   this.$setPristine = function() {
22967     ctrl.$dirty = false;
22968     ctrl.$pristine = true;
22969     $animate.removeClass($element, DIRTY_CLASS);
22970     $animate.addClass($element, PRISTINE_CLASS);
22971   };
22972
22973   /**
22974    * @ngdoc method
22975    * @name ngModel.NgModelController#$setDirty
22976    *
22977    * @description
22978    * Sets the control to its dirty state.
22979    *
22980    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
22981    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
22982    * from when first compiled.
22983    */
22984   this.$setDirty = function() {
22985     ctrl.$dirty = true;
22986     ctrl.$pristine = false;
22987     $animate.removeClass($element, PRISTINE_CLASS);
22988     $animate.addClass($element, DIRTY_CLASS);
22989     parentForm.$setDirty();
22990   };
22991
22992   /**
22993    * @ngdoc method
22994    * @name ngModel.NgModelController#$setUntouched
22995    *
22996    * @description
22997    * Sets the control to its untouched state.
22998    *
22999    * This method can be called to remove the `ng-touched` class and set the control to its
23000    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
23001    * by default, however this function can be used to restore that state if the model has
23002    * already been touched by the user.
23003    */
23004   this.$setUntouched = function() {
23005     ctrl.$touched = false;
23006     ctrl.$untouched = true;
23007     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
23008   };
23009
23010   /**
23011    * @ngdoc method
23012    * @name ngModel.NgModelController#$setTouched
23013    *
23014    * @description
23015    * Sets the control to its touched state.
23016    *
23017    * This method can be called to remove the `ng-untouched` class and set the control to its
23018    * touched state (`ng-touched` class). A model is considered to be touched when the user has
23019    * first focused the control element and then shifted focus away from the control (blur event).
23020    */
23021   this.$setTouched = function() {
23022     ctrl.$touched = true;
23023     ctrl.$untouched = false;
23024     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
23025   };
23026
23027   /**
23028    * @ngdoc method
23029    * @name ngModel.NgModelController#$rollbackViewValue
23030    *
23031    * @description
23032    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
23033    * which may be caused by a pending debounced event or because the input is waiting for a some
23034    * future event.
23035    *
23036    * If you have an input that uses `ng-model-options` to set up debounced events or events such
23037    * as blur you can have a situation where there is a period when the `$viewValue`
23038    * is out of synch with the ngModel's `$modelValue`.
23039    *
23040    * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
23041    * programmatically before these debounced/future events have resolved/occurred, because Angular's
23042    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
23043    *
23044    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
23045    * input which may have such events pending. This is important in order to make sure that the
23046    * input field will be updated with the new model value and any pending operations are cancelled.
23047    *
23048    * <example name="ng-model-cancel-update" module="cancel-update-example">
23049    *   <file name="app.js">
23050    *     angular.module('cancel-update-example', [])
23051    *
23052    *     .controller('CancelUpdateController', ['$scope', function($scope) {
23053    *       $scope.resetWithCancel = function(e) {
23054    *         if (e.keyCode == 27) {
23055    *           $scope.myForm.myInput1.$rollbackViewValue();
23056    *           $scope.myValue = '';
23057    *         }
23058    *       };
23059    *       $scope.resetWithoutCancel = function(e) {
23060    *         if (e.keyCode == 27) {
23061    *           $scope.myValue = '';
23062    *         }
23063    *       };
23064    *     }]);
23065    *   </file>
23066    *   <file name="index.html">
23067    *     <div ng-controller="CancelUpdateController">
23068    *       <p>Try typing something in each input.  See that the model only updates when you
23069    *          blur off the input.
23070    *        </p>
23071    *        <p>Now see what happens if you start typing then press the Escape key</p>
23072    *
23073    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
23074    *         <p>With $rollbackViewValue()</p>
23075    *         <input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)"><br/>
23076    *         myValue: "{{ myValue }}"
23077    *
23078    *         <p>Without $rollbackViewValue()</p>
23079    *         <input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)"><br/>
23080    *         myValue: "{{ myValue }}"
23081    *       </form>
23082    *     </div>
23083    *   </file>
23084    * </example>
23085    */
23086   this.$rollbackViewValue = function() {
23087     $timeout.cancel(pendingDebounce);
23088     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
23089     ctrl.$render();
23090   };
23091
23092   /**
23093    * @ngdoc method
23094    * @name ngModel.NgModelController#$validate
23095    *
23096    * @description
23097    * Runs each of the registered validators (first synchronous validators and then
23098    * asynchronous validators).
23099    * If the validity changes to invalid, the model will be set to `undefined`,
23100    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
23101    * If the validity changes to valid, it will set the model to the last available valid
23102    * modelValue, i.e. either the last parsed value or the last value set from the scope.
23103    */
23104   this.$validate = function() {
23105     // ignore $validate before model is initialized
23106     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
23107       return;
23108     }
23109
23110     var viewValue = ctrl.$$lastCommittedViewValue;
23111     // Note: we use the $$rawModelValue as $modelValue might have been
23112     // set to undefined during a view -> model update that found validation
23113     // errors. We can't parse the view here, since that could change
23114     // the model although neither viewValue nor the model on the scope changed
23115     var modelValue = ctrl.$$rawModelValue;
23116
23117     var prevValid = ctrl.$valid;
23118     var prevModelValue = ctrl.$modelValue;
23119
23120     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
23121
23122     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
23123       // If there was no change in validity, don't update the model
23124       // This prevents changing an invalid modelValue to undefined
23125       if (!allowInvalid && prevValid !== allValid) {
23126         // Note: Don't check ctrl.$valid here, as we could have
23127         // external validators (e.g. calculated on the server),
23128         // that just call $setValidity and need the model value
23129         // to calculate their validity.
23130         ctrl.$modelValue = allValid ? modelValue : undefined;
23131
23132         if (ctrl.$modelValue !== prevModelValue) {
23133           ctrl.$$writeModelToScope();
23134         }
23135       }
23136     });
23137
23138   };
23139
23140   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
23141     currentValidationRunId++;
23142     var localValidationRunId = currentValidationRunId;
23143
23144     // check parser error
23145     if (!processParseErrors()) {
23146       validationDone(false);
23147       return;
23148     }
23149     if (!processSyncValidators()) {
23150       validationDone(false);
23151       return;
23152     }
23153     processAsyncValidators();
23154
23155     function processParseErrors() {
23156       var errorKey = ctrl.$$parserName || 'parse';
23157       if (parserValid === undefined) {
23158         setValidity(errorKey, null);
23159       } else {
23160         if (!parserValid) {
23161           forEach(ctrl.$validators, function(v, name) {
23162             setValidity(name, null);
23163           });
23164           forEach(ctrl.$asyncValidators, function(v, name) {
23165             setValidity(name, null);
23166           });
23167         }
23168         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
23169         setValidity(errorKey, parserValid);
23170         return parserValid;
23171       }
23172       return true;
23173     }
23174
23175     function processSyncValidators() {
23176       var syncValidatorsValid = true;
23177       forEach(ctrl.$validators, function(validator, name) {
23178         var result = validator(modelValue, viewValue);
23179         syncValidatorsValid = syncValidatorsValid && result;
23180         setValidity(name, result);
23181       });
23182       if (!syncValidatorsValid) {
23183         forEach(ctrl.$asyncValidators, function(v, name) {
23184           setValidity(name, null);
23185         });
23186         return false;
23187       }
23188       return true;
23189     }
23190
23191     function processAsyncValidators() {
23192       var validatorPromises = [];
23193       var allValid = true;
23194       forEach(ctrl.$asyncValidators, function(validator, name) {
23195         var promise = validator(modelValue, viewValue);
23196         if (!isPromiseLike(promise)) {
23197           throw $ngModelMinErr("$asyncValidators",
23198             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
23199         }
23200         setValidity(name, undefined);
23201         validatorPromises.push(promise.then(function() {
23202           setValidity(name, true);
23203         }, function(error) {
23204           allValid = false;
23205           setValidity(name, false);
23206         }));
23207       });
23208       if (!validatorPromises.length) {
23209         validationDone(true);
23210       } else {
23211         $q.all(validatorPromises).then(function() {
23212           validationDone(allValid);
23213         }, noop);
23214       }
23215     }
23216
23217     function setValidity(name, isValid) {
23218       if (localValidationRunId === currentValidationRunId) {
23219         ctrl.$setValidity(name, isValid);
23220       }
23221     }
23222
23223     function validationDone(allValid) {
23224       if (localValidationRunId === currentValidationRunId) {
23225
23226         doneCallback(allValid);
23227       }
23228     }
23229   };
23230
23231   /**
23232    * @ngdoc method
23233    * @name ngModel.NgModelController#$commitViewValue
23234    *
23235    * @description
23236    * Commit a pending update to the `$modelValue`.
23237    *
23238    * Updates may be pending by a debounced event or because the input is waiting for a some future
23239    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
23240    * usually handles calling this in response to input events.
23241    */
23242   this.$commitViewValue = function() {
23243     var viewValue = ctrl.$viewValue;
23244
23245     $timeout.cancel(pendingDebounce);
23246
23247     // If the view value has not changed then we should just exit, except in the case where there is
23248     // a native validator on the element. In this case the validation state may have changed even though
23249     // the viewValue has stayed empty.
23250     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
23251       return;
23252     }
23253     ctrl.$$lastCommittedViewValue = viewValue;
23254
23255     // change to dirty
23256     if (ctrl.$pristine) {
23257       this.$setDirty();
23258     }
23259     this.$$parseAndValidate();
23260   };
23261
23262   this.$$parseAndValidate = function() {
23263     var viewValue = ctrl.$$lastCommittedViewValue;
23264     var modelValue = viewValue;
23265     parserValid = isUndefined(modelValue) ? undefined : true;
23266
23267     if (parserValid) {
23268       for (var i = 0; i < ctrl.$parsers.length; i++) {
23269         modelValue = ctrl.$parsers[i](modelValue);
23270         if (isUndefined(modelValue)) {
23271           parserValid = false;
23272           break;
23273         }
23274       }
23275     }
23276     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
23277       // ctrl.$modelValue has not been touched yet...
23278       ctrl.$modelValue = ngModelGet($scope);
23279     }
23280     var prevModelValue = ctrl.$modelValue;
23281     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
23282     ctrl.$$rawModelValue = modelValue;
23283
23284     if (allowInvalid) {
23285       ctrl.$modelValue = modelValue;
23286       writeToModelIfNeeded();
23287     }
23288
23289     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
23290     // This can happen if e.g. $setViewValue is called from inside a parser
23291     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
23292       if (!allowInvalid) {
23293         // Note: Don't check ctrl.$valid here, as we could have
23294         // external validators (e.g. calculated on the server),
23295         // that just call $setValidity and need the model value
23296         // to calculate their validity.
23297         ctrl.$modelValue = allValid ? modelValue : undefined;
23298         writeToModelIfNeeded();
23299       }
23300     });
23301
23302     function writeToModelIfNeeded() {
23303       if (ctrl.$modelValue !== prevModelValue) {
23304         ctrl.$$writeModelToScope();
23305       }
23306     }
23307   };
23308
23309   this.$$writeModelToScope = function() {
23310     ngModelSet($scope, ctrl.$modelValue);
23311     forEach(ctrl.$viewChangeListeners, function(listener) {
23312       try {
23313         listener();
23314       } catch (e) {
23315         $exceptionHandler(e);
23316       }
23317     });
23318   };
23319
23320   /**
23321    * @ngdoc method
23322    * @name ngModel.NgModelController#$setViewValue
23323    *
23324    * @description
23325    * Update the view value.
23326    *
23327    * This method should be called when an input directive want to change the view value; typically,
23328    * this is done from within a DOM event handler.
23329    *
23330    * For example {@link ng.directive:input input} calls it when the value of the input changes and
23331    * {@link ng.directive:select select} calls it when an option is selected.
23332    *
23333    * If the new `value` is an object (rather than a string or a number), we should make a copy of the
23334    * object before passing it to `$setViewValue`.  This is because `ngModel` does not perform a deep
23335    * watch of objects, it only looks for a change of identity. If you only change the property of
23336    * the object then ngModel will not realise that the object has changed and will not invoke the
23337    * `$parsers` and `$validators` pipelines.
23338    *
23339    * For this reason, you should not change properties of the copy once it has been passed to
23340    * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
23341    *
23342    * When this method is called, the new `value` will be staged for committing through the `$parsers`
23343    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
23344    * value sent directly for processing, finally to be applied to `$modelValue` and then the
23345    * **expression** specified in the `ng-model` attribute.
23346    *
23347    * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
23348    *
23349    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
23350    * and the `default` trigger is not listed, all those actions will remain pending until one of the
23351    * `updateOn` events is triggered on the DOM element.
23352    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
23353    * directive is used with a custom debounce for this particular event.
23354    *
23355    * Note that calling this function does not trigger a `$digest`.
23356    *
23357    * @param {string} value Value from the view.
23358    * @param {string} trigger Event that triggered the update.
23359    */
23360   this.$setViewValue = function(value, trigger) {
23361     ctrl.$viewValue = value;
23362     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
23363       ctrl.$$debounceViewValueCommit(trigger);
23364     }
23365   };
23366
23367   this.$$debounceViewValueCommit = function(trigger) {
23368     var debounceDelay = 0,
23369         options = ctrl.$options,
23370         debounce;
23371
23372     if (options && isDefined(options.debounce)) {
23373       debounce = options.debounce;
23374       if (isNumber(debounce)) {
23375         debounceDelay = debounce;
23376       } else if (isNumber(debounce[trigger])) {
23377         debounceDelay = debounce[trigger];
23378       } else if (isNumber(debounce['default'])) {
23379         debounceDelay = debounce['default'];
23380       }
23381     }
23382
23383     $timeout.cancel(pendingDebounce);
23384     if (debounceDelay) {
23385       pendingDebounce = $timeout(function() {
23386         ctrl.$commitViewValue();
23387       }, debounceDelay);
23388     } else if ($rootScope.$$phase) {
23389       ctrl.$commitViewValue();
23390     } else {
23391       $scope.$apply(function() {
23392         ctrl.$commitViewValue();
23393       });
23394     }
23395   };
23396
23397   // model -> value
23398   // Note: we cannot use a normal scope.$watch as we want to detect the following:
23399   // 1. scope value is 'a'
23400   // 2. user enters 'b'
23401   // 3. ng-change kicks in and reverts scope value to 'a'
23402   //    -> scope value did not change since the last digest as
23403   //       ng-change executes in apply phase
23404   // 4. view should be changed back to 'a'
23405   $scope.$watch(function ngModelWatch() {
23406     var modelValue = ngModelGet($scope);
23407
23408     // if scope model value and ngModel value are out of sync
23409     // TODO(perf): why not move this to the action fn?
23410     if (modelValue !== ctrl.$modelValue) {
23411       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
23412       parserValid = undefined;
23413
23414       var formatters = ctrl.$formatters,
23415           idx = formatters.length;
23416
23417       var viewValue = modelValue;
23418       while (idx--) {
23419         viewValue = formatters[idx](viewValue);
23420       }
23421       if (ctrl.$viewValue !== viewValue) {
23422         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
23423         ctrl.$render();
23424
23425         ctrl.$$runValidators(modelValue, viewValue, noop);
23426       }
23427     }
23428
23429     return modelValue;
23430   });
23431 }];
23432
23433
23434 /**
23435  * @ngdoc directive
23436  * @name ngModel
23437  *
23438  * @element input
23439  * @priority 1
23440  *
23441  * @description
23442  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
23443  * property on the scope using {@link ngModel.NgModelController NgModelController},
23444  * which is created and exposed by this directive.
23445  *
23446  * `ngModel` is responsible for:
23447  *
23448  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
23449  *   require.
23450  * - Providing validation behavior (i.e. required, number, email, url).
23451  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
23452  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
23453  * - Registering the control with its parent {@link ng.directive:form form}.
23454  *
23455  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
23456  * current scope. If the property doesn't already exist on this scope, it will be created
23457  * implicitly and added to the scope.
23458  *
23459  * For best practices on using `ngModel`, see:
23460  *
23461  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
23462  *
23463  * For basic examples, how to use `ngModel`, see:
23464  *
23465  *  - {@link ng.directive:input input}
23466  *    - {@link input[text] text}
23467  *    - {@link input[checkbox] checkbox}
23468  *    - {@link input[radio] radio}
23469  *    - {@link input[number] number}
23470  *    - {@link input[email] email}
23471  *    - {@link input[url] url}
23472  *    - {@link input[date] date}
23473  *    - {@link input[datetime-local] datetime-local}
23474  *    - {@link input[time] time}
23475  *    - {@link input[month] month}
23476  *    - {@link input[week] week}
23477  *  - {@link ng.directive:select select}
23478  *  - {@link ng.directive:textarea textarea}
23479  *
23480  * # CSS classes
23481  * The following CSS classes are added and removed on the associated input/select/textarea element
23482  * depending on the validity of the model.
23483  *
23484  *  - `ng-valid`: the model is valid
23485  *  - `ng-invalid`: the model is invalid
23486  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
23487  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
23488  *  - `ng-pristine`: the control hasn't been interacted with yet
23489  *  - `ng-dirty`: the control has been interacted with
23490  *  - `ng-touched`: the control has been blurred
23491  *  - `ng-untouched`: the control hasn't been blurred
23492  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
23493  *
23494  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
23495  *
23496  * ## Animation Hooks
23497  *
23498  * Animations within models are triggered when any of the associated CSS classes are added and removed
23499  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
23500  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
23501  * The animations that are triggered within ngModel are similar to how they work in ngClass and
23502  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
23503  *
23504  * The following example shows a simple way to utilize CSS transitions to style an input element
23505  * that has been rendered as invalid after it has been validated:
23506  *
23507  * <pre>
23508  * //be sure to include ngAnimate as a module to hook into more
23509  * //advanced animations
23510  * .my-input {
23511  *   transition:0.5s linear all;
23512  *   background: white;
23513  * }
23514  * .my-input.ng-invalid {
23515  *   background: red;
23516  *   color:white;
23517  * }
23518  * </pre>
23519  *
23520  * @example
23521  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
23522      <file name="index.html">
23523        <script>
23524         angular.module('inputExample', [])
23525           .controller('ExampleController', ['$scope', function($scope) {
23526             $scope.val = '1';
23527           }]);
23528        </script>
23529        <style>
23530          .my-input {
23531            -webkit-transition:all linear 0.5s;
23532            transition:all linear 0.5s;
23533            background: transparent;
23534          }
23535          .my-input.ng-invalid {
23536            color:white;
23537            background: red;
23538          }
23539        </style>
23540        Update input to see transitions when valid/invalid.
23541        Integer is a valid value.
23542        <form name="testForm" ng-controller="ExampleController">
23543          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
23544        </form>
23545      </file>
23546  * </example>
23547  *
23548  * ## Binding to a getter/setter
23549  *
23550  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
23551  * function that returns a representation of the model when called with zero arguments, and sets
23552  * the internal state of a model when called with an argument. It's sometimes useful to use this
23553  * for models that have an internal representation that's different than what the model exposes
23554  * to the view.
23555  *
23556  * <div class="alert alert-success">
23557  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
23558  * frequently than other parts of your code.
23559  * </div>
23560  *
23561  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
23562  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
23563  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
23564  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
23565  *
23566  * The following example shows how to use `ngModel` with a getter/setter:
23567  *
23568  * @example
23569  * <example name="ngModel-getter-setter" module="getterSetterExample">
23570      <file name="index.html">
23571        <div ng-controller="ExampleController">
23572          <form name="userForm">
23573            Name:
23574            <input type="text" name="userName"
23575                   ng-model="user.name"
23576                   ng-model-options="{ getterSetter: true }" />
23577          </form>
23578          <pre>user.name = <span ng-bind="user.name()"></span></pre>
23579        </div>
23580      </file>
23581      <file name="app.js">
23582        angular.module('getterSetterExample', [])
23583          .controller('ExampleController', ['$scope', function($scope) {
23584            var _name = 'Brian';
23585            $scope.user = {
23586              name: function(newName) {
23587                if (angular.isDefined(newName)) {
23588                  _name = newName;
23589                }
23590                return _name;
23591              }
23592            };
23593          }]);
23594      </file>
23595  * </example>
23596  */
23597 var ngModelDirective = ['$rootScope', function($rootScope) {
23598   return {
23599     restrict: 'A',
23600     require: ['ngModel', '^?form', '^?ngModelOptions'],
23601     controller: NgModelController,
23602     // Prelink needs to run before any input directive
23603     // so that we can set the NgModelOptions in NgModelController
23604     // before anyone else uses it.
23605     priority: 1,
23606     compile: function ngModelCompile(element) {
23607       // Setup initial state of the control
23608       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
23609
23610       return {
23611         pre: function ngModelPreLink(scope, element, attr, ctrls) {
23612           var modelCtrl = ctrls[0],
23613               formCtrl = ctrls[1] || nullFormCtrl;
23614
23615           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
23616
23617           // notify others, especially parent forms
23618           formCtrl.$addControl(modelCtrl);
23619
23620           attr.$observe('name', function(newValue) {
23621             if (modelCtrl.$name !== newValue) {
23622               formCtrl.$$renameControl(modelCtrl, newValue);
23623             }
23624           });
23625
23626           scope.$on('$destroy', function() {
23627             formCtrl.$removeControl(modelCtrl);
23628           });
23629         },
23630         post: function ngModelPostLink(scope, element, attr, ctrls) {
23631           var modelCtrl = ctrls[0];
23632           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
23633             element.on(modelCtrl.$options.updateOn, function(ev) {
23634               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
23635             });
23636           }
23637
23638           element.on('blur', function(ev) {
23639             if (modelCtrl.$touched) return;
23640
23641             if ($rootScope.$$phase) {
23642               scope.$evalAsync(modelCtrl.$setTouched);
23643             } else {
23644               scope.$apply(modelCtrl.$setTouched);
23645             }
23646           });
23647         }
23648       };
23649     }
23650   };
23651 }];
23652
23653 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
23654
23655 /**
23656  * @ngdoc directive
23657  * @name ngModelOptions
23658  *
23659  * @description
23660  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
23661  * events that will trigger a model update and/or a debouncing delay so that the actual update only
23662  * takes place when a timer expires; this timer will be reset after another change takes place.
23663  *
23664  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
23665  * be different than the value in the actual model. This means that if you update the model you
23666  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
23667  * order to make sure it is synchronized with the model and that any debounced action is canceled.
23668  *
23669  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
23670  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
23671  * important because `form` controllers are published to the related scope under the name in their
23672  * `name` attribute.
23673  *
23674  * Any pending changes will take place immediately when an enclosing form is submitted via the
23675  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
23676  * to have access to the updated model.
23677  *
23678  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
23679  *
23680  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
23681  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
23682  *     events using an space delimited list. There is a special event called `default` that
23683  *     matches the default events belonging of the control.
23684  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
23685  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
23686  *     custom value for each event. For example:
23687  *     `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
23688  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
23689  *     not validate correctly instead of the default behavior of setting the model to undefined.
23690  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
23691        `ngModel` as getters/setters.
23692  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
23693  *     `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
23694  *     otherwise the default timezone of the browser will be used.
23695  *
23696  * @example
23697
23698   The following example shows how to override immediate updates. Changes on the inputs within the
23699   form will update the model only when the control loses focus (blur event). If `escape` key is
23700   pressed while the input field is focused, the value is reset to the value in the current model.
23701
23702   <example name="ngModelOptions-directive-blur" module="optionsExample">
23703     <file name="index.html">
23704       <div ng-controller="ExampleController">
23705         <form name="userForm">
23706           Name:
23707           <input type="text" name="userName"
23708                  ng-model="user.name"
23709                  ng-model-options="{ updateOn: 'blur' }"
23710                  ng-keyup="cancel($event)" /><br />
23711
23712           Other data:
23713           <input type="text" ng-model="user.data" /><br />
23714         </form>
23715         <pre>user.name = <span ng-bind="user.name"></span></pre>
23716       </div>
23717     </file>
23718     <file name="app.js">
23719       angular.module('optionsExample', [])
23720         .controller('ExampleController', ['$scope', function($scope) {
23721           $scope.user = { name: 'say', data: '' };
23722
23723           $scope.cancel = function(e) {
23724             if (e.keyCode == 27) {
23725               $scope.userForm.userName.$rollbackViewValue();
23726             }
23727           };
23728         }]);
23729     </file>
23730     <file name="protractor.js" type="protractor">
23731       var model = element(by.binding('user.name'));
23732       var input = element(by.model('user.name'));
23733       var other = element(by.model('user.data'));
23734
23735       it('should allow custom events', function() {
23736         input.sendKeys(' hello');
23737         input.click();
23738         expect(model.getText()).toEqual('say');
23739         other.click();
23740         expect(model.getText()).toEqual('say hello');
23741       });
23742
23743       it('should $rollbackViewValue when model changes', function() {
23744         input.sendKeys(' hello');
23745         expect(input.getAttribute('value')).toEqual('say hello');
23746         input.sendKeys(protractor.Key.ESCAPE);
23747         expect(input.getAttribute('value')).toEqual('say');
23748         other.click();
23749         expect(model.getText()).toEqual('say');
23750       });
23751     </file>
23752   </example>
23753
23754   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
23755   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
23756
23757   <example name="ngModelOptions-directive-debounce" module="optionsExample">
23758     <file name="index.html">
23759       <div ng-controller="ExampleController">
23760         <form name="userForm">
23761           Name:
23762           <input type="text" name="userName"
23763                  ng-model="user.name"
23764                  ng-model-options="{ debounce: 1000 }" />
23765           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
23766         </form>
23767         <pre>user.name = <span ng-bind="user.name"></span></pre>
23768       </div>
23769     </file>
23770     <file name="app.js">
23771       angular.module('optionsExample', [])
23772         .controller('ExampleController', ['$scope', function($scope) {
23773           $scope.user = { name: 'say' };
23774         }]);
23775     </file>
23776   </example>
23777
23778   This one shows how to bind to getter/setters:
23779
23780   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
23781     <file name="index.html">
23782       <div ng-controller="ExampleController">
23783         <form name="userForm">
23784           Name:
23785           <input type="text" name="userName"
23786                  ng-model="user.name"
23787                  ng-model-options="{ getterSetter: true }" />
23788         </form>
23789         <pre>user.name = <span ng-bind="user.name()"></span></pre>
23790       </div>
23791     </file>
23792     <file name="app.js">
23793       angular.module('getterSetterExample', [])
23794         .controller('ExampleController', ['$scope', function($scope) {
23795           var _name = 'Brian';
23796           $scope.user = {
23797             name: function(newName) {
23798               return angular.isDefined(newName) ? (_name = newName) : _name;
23799             }
23800           };
23801         }]);
23802     </file>
23803   </example>
23804  */
23805 var ngModelOptionsDirective = function() {
23806   return {
23807     restrict: 'A',
23808     controller: ['$scope', '$attrs', function($scope, $attrs) {
23809       var that = this;
23810       this.$options = $scope.$eval($attrs.ngModelOptions);
23811       // Allow adding/overriding bound events
23812       if (this.$options.updateOn !== undefined) {
23813         this.$options.updateOnDefault = false;
23814         // extract "default" pseudo-event from list of events that can trigger a model update
23815         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
23816           that.$options.updateOnDefault = true;
23817           return ' ';
23818         }));
23819       } else {
23820         this.$options.updateOnDefault = true;
23821       }
23822     }]
23823   };
23824 };
23825
23826
23827
23828 // helper methods
23829 function addSetValidityMethod(context) {
23830   var ctrl = context.ctrl,
23831       $element = context.$element,
23832       classCache = {},
23833       set = context.set,
23834       unset = context.unset,
23835       parentForm = context.parentForm,
23836       $animate = context.$animate;
23837
23838   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
23839
23840   ctrl.$setValidity = setValidity;
23841
23842   function setValidity(validationErrorKey, state, controller) {
23843     if (state === undefined) {
23844       createAndSet('$pending', validationErrorKey, controller);
23845     } else {
23846       unsetAndCleanup('$pending', validationErrorKey, controller);
23847     }
23848     if (!isBoolean(state)) {
23849       unset(ctrl.$error, validationErrorKey, controller);
23850       unset(ctrl.$$success, validationErrorKey, controller);
23851     } else {
23852       if (state) {
23853         unset(ctrl.$error, validationErrorKey, controller);
23854         set(ctrl.$$success, validationErrorKey, controller);
23855       } else {
23856         set(ctrl.$error, validationErrorKey, controller);
23857         unset(ctrl.$$success, validationErrorKey, controller);
23858       }
23859     }
23860     if (ctrl.$pending) {
23861       cachedToggleClass(PENDING_CLASS, true);
23862       ctrl.$valid = ctrl.$invalid = undefined;
23863       toggleValidationCss('', null);
23864     } else {
23865       cachedToggleClass(PENDING_CLASS, false);
23866       ctrl.$valid = isObjectEmpty(ctrl.$error);
23867       ctrl.$invalid = !ctrl.$valid;
23868       toggleValidationCss('', ctrl.$valid);
23869     }
23870
23871     // re-read the state as the set/unset methods could have
23872     // combined state in ctrl.$error[validationError] (used for forms),
23873     // where setting/unsetting only increments/decrements the value,
23874     // and does not replace it.
23875     var combinedState;
23876     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
23877       combinedState = undefined;
23878     } else if (ctrl.$error[validationErrorKey]) {
23879       combinedState = false;
23880     } else if (ctrl.$$success[validationErrorKey]) {
23881       combinedState = true;
23882     } else {
23883       combinedState = null;
23884     }
23885
23886     toggleValidationCss(validationErrorKey, combinedState);
23887     parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
23888   }
23889
23890   function createAndSet(name, value, controller) {
23891     if (!ctrl[name]) {
23892       ctrl[name] = {};
23893     }
23894     set(ctrl[name], value, controller);
23895   }
23896
23897   function unsetAndCleanup(name, value, controller) {
23898     if (ctrl[name]) {
23899       unset(ctrl[name], value, controller);
23900     }
23901     if (isObjectEmpty(ctrl[name])) {
23902       ctrl[name] = undefined;
23903     }
23904   }
23905
23906   function cachedToggleClass(className, switchValue) {
23907     if (switchValue && !classCache[className]) {
23908       $animate.addClass($element, className);
23909       classCache[className] = true;
23910     } else if (!switchValue && classCache[className]) {
23911       $animate.removeClass($element, className);
23912       classCache[className] = false;
23913     }
23914   }
23915
23916   function toggleValidationCss(validationErrorKey, isValid) {
23917     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
23918
23919     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
23920     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
23921   }
23922 }
23923
23924 function isObjectEmpty(obj) {
23925   if (obj) {
23926     for (var prop in obj) {
23927       return false;
23928     }
23929   }
23930   return true;
23931 }
23932
23933 /**
23934  * @ngdoc directive
23935  * @name ngNonBindable
23936  * @restrict AC
23937  * @priority 1000
23938  *
23939  * @description
23940  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
23941  * DOM element. This is useful if the element contains what appears to be Angular directives and
23942  * bindings but which should be ignored by Angular. This could be the case if you have a site that
23943  * displays snippets of code, for instance.
23944  *
23945  * @element ANY
23946  *
23947  * @example
23948  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
23949  * but the one wrapped in `ngNonBindable` is left alone.
23950  *
23951  * @example
23952     <example>
23953       <file name="index.html">
23954         <div>Normal: {{1 + 2}}</div>
23955         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
23956       </file>
23957       <file name="protractor.js" type="protractor">
23958        it('should check ng-non-bindable', function() {
23959          expect(element(by.binding('1 + 2')).getText()).toContain('3');
23960          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
23961        });
23962       </file>
23963     </example>
23964  */
23965 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
23966
23967 /**
23968  * @ngdoc directive
23969  * @name ngPluralize
23970  * @restrict EA
23971  *
23972  * @description
23973  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
23974  * These rules are bundled with angular.js, but can be overridden
23975  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
23976  * by specifying the mappings between
23977  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
23978  * and the strings to be displayed.
23979  *
23980  * # Plural categories and explicit number rules
23981  * There are two
23982  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
23983  * in Angular's default en-US locale: "one" and "other".
23984  *
23985  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
23986  * any number that is not 1), an explicit number rule can only match one number. For example, the
23987  * explicit number rule for "3" matches the number 3. There are examples of plural categories
23988  * and explicit number rules throughout the rest of this documentation.
23989  *
23990  * # Configuring ngPluralize
23991  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
23992  * You can also provide an optional attribute, `offset`.
23993  *
23994  * The value of the `count` attribute can be either a string or an {@link guide/expression
23995  * Angular expression}; these are evaluated on the current scope for its bound value.
23996  *
23997  * The `when` attribute specifies the mappings between plural categories and the actual
23998  * string to be displayed. The value of the attribute should be a JSON object.
23999  *
24000  * The following example shows how to configure ngPluralize:
24001  *
24002  * ```html
24003  * <ng-pluralize count="personCount"
24004                  when="{'0': 'Nobody is viewing.',
24005  *                      'one': '1 person is viewing.',
24006  *                      'other': '{} people are viewing.'}">
24007  * </ng-pluralize>
24008  *```
24009  *
24010  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
24011  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
24012  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
24013  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
24014  * show "a dozen people are viewing".
24015  *
24016  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
24017  * into pluralized strings. In the previous example, Angular will replace `{}` with
24018  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
24019  * for <span ng-non-bindable>{{numberExpression}}</span>.
24020  *
24021  * # Configuring ngPluralize with offset
24022  * The `offset` attribute allows further customization of pluralized text, which can result in
24023  * a better user experience. For example, instead of the message "4 people are viewing this document",
24024  * you might display "John, Kate and 2 others are viewing this document".
24025  * The offset attribute allows you to offset a number by any desired value.
24026  * Let's take a look at an example:
24027  *
24028  * ```html
24029  * <ng-pluralize count="personCount" offset=2
24030  *               when="{'0': 'Nobody is viewing.',
24031  *                      '1': '{{person1}} is viewing.',
24032  *                      '2': '{{person1}} and {{person2}} are viewing.',
24033  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
24034  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
24035  * </ng-pluralize>
24036  * ```
24037  *
24038  * Notice that we are still using two plural categories(one, other), but we added
24039  * three explicit number rules 0, 1 and 2.
24040  * When one person, perhaps John, views the document, "John is viewing" will be shown.
24041  * When three people view the document, no explicit number rule is found, so
24042  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
24043  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
24044  * is shown.
24045  *
24046  * Note that when you specify offsets, you must provide explicit number rules for
24047  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
24048  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
24049  * plural categories "one" and "other".
24050  *
24051  * @param {string|expression} count The variable to be bound to.
24052  * @param {string} when The mapping between plural category to its corresponding strings.
24053  * @param {number=} offset Offset to deduct from the total number.
24054  *
24055  * @example
24056     <example module="pluralizeExample">
24057       <file name="index.html">
24058         <script>
24059           angular.module('pluralizeExample', [])
24060             .controller('ExampleController', ['$scope', function($scope) {
24061               $scope.person1 = 'Igor';
24062               $scope.person2 = 'Misko';
24063               $scope.personCount = 1;
24064             }]);
24065         </script>
24066         <div ng-controller="ExampleController">
24067           Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
24068           Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
24069           Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
24070
24071           <!--- Example with simple pluralization rules for en locale --->
24072           Without Offset:
24073           <ng-pluralize count="personCount"
24074                         when="{'0': 'Nobody is viewing.',
24075                                'one': '1 person is viewing.',
24076                                'other': '{} people are viewing.'}">
24077           </ng-pluralize><br>
24078
24079           <!--- Example with offset --->
24080           With Offset(2):
24081           <ng-pluralize count="personCount" offset=2
24082                         when="{'0': 'Nobody is viewing.',
24083                                '1': '{{person1}} is viewing.',
24084                                '2': '{{person1}} and {{person2}} are viewing.',
24085                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
24086                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
24087           </ng-pluralize>
24088         </div>
24089       </file>
24090       <file name="protractor.js" type="protractor">
24091         it('should show correct pluralized string', function() {
24092           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
24093           var withOffset = element.all(by.css('ng-pluralize')).get(1);
24094           var countInput = element(by.model('personCount'));
24095
24096           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
24097           expect(withOffset.getText()).toEqual('Igor is viewing.');
24098
24099           countInput.clear();
24100           countInput.sendKeys('0');
24101
24102           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
24103           expect(withOffset.getText()).toEqual('Nobody is viewing.');
24104
24105           countInput.clear();
24106           countInput.sendKeys('2');
24107
24108           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
24109           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
24110
24111           countInput.clear();
24112           countInput.sendKeys('3');
24113
24114           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
24115           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
24116
24117           countInput.clear();
24118           countInput.sendKeys('4');
24119
24120           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
24121           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
24122         });
24123         it('should show data-bound names', function() {
24124           var withOffset = element.all(by.css('ng-pluralize')).get(1);
24125           var personCount = element(by.model('personCount'));
24126           var person1 = element(by.model('person1'));
24127           var person2 = element(by.model('person2'));
24128           personCount.clear();
24129           personCount.sendKeys('4');
24130           person1.clear();
24131           person1.sendKeys('Di');
24132           person2.clear();
24133           person2.sendKeys('Vojta');
24134           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
24135         });
24136       </file>
24137     </example>
24138  */
24139 var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
24140   var BRACE = /{}/g,
24141       IS_WHEN = /^when(Minus)?(.+)$/;
24142
24143   return {
24144     restrict: 'EA',
24145     link: function(scope, element, attr) {
24146       var numberExp = attr.count,
24147           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
24148           offset = attr.offset || 0,
24149           whens = scope.$eval(whenExp) || {},
24150           whensExpFns = {},
24151           startSymbol = $interpolate.startSymbol(),
24152           endSymbol = $interpolate.endSymbol(),
24153           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
24154           watchRemover = angular.noop,
24155           lastCount;
24156
24157       forEach(attr, function(expression, attributeName) {
24158         var tmpMatch = IS_WHEN.exec(attributeName);
24159         if (tmpMatch) {
24160           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
24161           whens[whenKey] = element.attr(attr.$attr[attributeName]);
24162         }
24163       });
24164       forEach(whens, function(expression, key) {
24165         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
24166
24167       });
24168
24169       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
24170         var count = parseFloat(newVal);
24171         var countIsNaN = isNaN(count);
24172
24173         if (!countIsNaN && !(count in whens)) {
24174           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
24175           // Otherwise, check it against pluralization rules in $locale service.
24176           count = $locale.pluralCat(count - offset);
24177         }
24178
24179         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
24180         // In JS `NaN !== NaN`, so we have to exlicitly check.
24181         if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
24182           watchRemover();
24183           watchRemover = scope.$watch(whensExpFns[count], updateElementText);
24184           lastCount = count;
24185         }
24186       });
24187
24188       function updateElementText(newText) {
24189         element.text(newText || '');
24190       }
24191     }
24192   };
24193 }];
24194
24195 /**
24196  * @ngdoc directive
24197  * @name ngRepeat
24198  *
24199  * @description
24200  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
24201  * instance gets its own scope, where the given loop variable is set to the current collection item,
24202  * and `$index` is set to the item index or key.
24203  *
24204  * Special properties are exposed on the local scope of each template instance, including:
24205  *
24206  * | Variable  | Type            | Details                                                                     |
24207  * |-----------|-----------------|-----------------------------------------------------------------------------|
24208  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
24209  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
24210  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
24211  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
24212  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
24213  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
24214  *
24215  * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
24216  * This may be useful when, for instance, nesting ngRepeats.
24217  *
24218  * # Iterating over object properties
24219  *
24220  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
24221  * syntax:
24222  *
24223  * ```js
24224  * <div ng-repeat="(key, value) in myObj"> ... </div>
24225  * ```
24226  *
24227  * You need to be aware that the JavaScript specification does not define what order
24228  * it will return the keys for an object. In order to have a guaranteed deterministic order
24229  * for the keys, Angular versions up to and including 1.3 **sort the keys alphabetically**.
24230  *
24231  * If this is not desired, the recommended workaround is to convert your object into an array
24232  * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
24233  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
24234  * or implement a `$watch` on the object yourself.
24235  *
24236  * In version 1.4 we will remove the sorting, since it seems that browsers generally follow the
24237  * strategy of providing keys in the order in which they were defined, although there are exceptions
24238  * when keys are deleted and reinstated.
24239  *
24240  *
24241  * # Tracking and Duplicates
24242  *
24243  * When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
24244  *
24245  * * When an item is added, a new instance of the template is added to the DOM.
24246  * * When an item is removed, its template instance is removed from the DOM.
24247  * * When items are reordered, their respective templates are reordered in the DOM.
24248  *
24249  * By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
24250  * there are duplicates, it is not possible to maintain a one-to-one mapping between collection
24251  * items and DOM elements.
24252  *
24253  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
24254  * with your own using the `track by` expression.
24255  *
24256  * For example, you may track items by the index of each item in the collection, using the
24257  * special scope property `$index`:
24258  * ```html
24259  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
24260  *      {{n}}
24261  *    </div>
24262  * ```
24263  *
24264  * You may use arbitrary expressions in `track by`, including references to custom functions
24265  * on the scope:
24266  * ```html
24267  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
24268  *      {{n}}
24269  *    </div>
24270  * ```
24271  *
24272  * If you are working with objects that have an identifier property, you can track
24273  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
24274  * will not have to rebuild the DOM elements for items it has already rendered, even if the
24275  * JavaScript objects in the collection have been substituted for new ones:
24276  * ```html
24277  *    <div ng-repeat="model in collection track by model.id">
24278  *      {{model.name}}
24279  *    </div>
24280  * ```
24281  *
24282  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
24283  * `$id` function, which tracks items by their identity:
24284  * ```html
24285  *    <div ng-repeat="obj in collection track by $id(obj)">
24286  *      {{obj.prop}}
24287  *    </div>
24288  * ```
24289  *
24290  * # Special repeat start and end points
24291  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
24292  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
24293  * 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)
24294  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
24295  *
24296  * The example below makes use of this feature:
24297  * ```html
24298  *   <header ng-repeat-start="item in items">
24299  *     Header {{ item }}
24300  *   </header>
24301  *   <div class="body">
24302  *     Body {{ item }}
24303  *   </div>
24304  *   <footer ng-repeat-end>
24305  *     Footer {{ item }}
24306  *   </footer>
24307  * ```
24308  *
24309  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
24310  * ```html
24311  *   <header>
24312  *     Header A
24313  *   </header>
24314  *   <div class="body">
24315  *     Body A
24316  *   </div>
24317  *   <footer>
24318  *     Footer A
24319  *   </footer>
24320  *   <header>
24321  *     Header B
24322  *   </header>
24323  *   <div class="body">
24324  *     Body B
24325  *   </div>
24326  *   <footer>
24327  *     Footer B
24328  *   </footer>
24329  * ```
24330  *
24331  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
24332  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
24333  *
24334  * @animations
24335  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
24336  *
24337  * **.leave** - when an item is removed from the list or when an item is filtered out
24338  *
24339  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
24340  *
24341  * @element ANY
24342  * @scope
24343  * @priority 1000
24344  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
24345  *   formats are currently supported:
24346  *
24347  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
24348  *     is a scope expression giving the collection to enumerate.
24349  *
24350  *     For example: `album in artist.albums`.
24351  *
24352  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
24353  *     and `expression` is the scope expression giving the collection to enumerate.
24354  *
24355  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
24356  *
24357  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
24358  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
24359  *     is specified, ng-repeat associates elements by identity. It is an error to have
24360  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
24361  *     mapped to the same DOM element, which is not possible.)  If filters are used in the expression, they should be
24362  *     applied before the tracking expression.
24363  *
24364  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
24365  *     will be associated by item identity in the array.
24366  *
24367  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
24368  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
24369  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
24370  *     element in the same way in the DOM.
24371  *
24372  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
24373  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
24374  *     property is same.
24375  *
24376  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
24377  *     to items in conjunction with a tracking expression.
24378  *
24379  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
24380  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
24381  *     when a filter is active on the repeater, but the filtered result set is empty.
24382  *
24383  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
24384  *     the items have been processed through the filter.
24385  *
24386  * @example
24387  * This example initializes the scope to a list of names and
24388  * then uses `ngRepeat` to display every person:
24389   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24390     <file name="index.html">
24391       <div ng-init="friends = [
24392         {name:'John', age:25, gender:'boy'},
24393         {name:'Jessie', age:30, gender:'girl'},
24394         {name:'Johanna', age:28, gender:'girl'},
24395         {name:'Joy', age:15, gender:'girl'},
24396         {name:'Mary', age:28, gender:'girl'},
24397         {name:'Peter', age:95, gender:'boy'},
24398         {name:'Sebastian', age:50, gender:'boy'},
24399         {name:'Erika', age:27, gender:'girl'},
24400         {name:'Patrick', age:40, gender:'boy'},
24401         {name:'Samantha', age:60, gender:'girl'}
24402       ]">
24403         I have {{friends.length}} friends. They are:
24404         <input type="search" ng-model="q" placeholder="filter friends..." />
24405         <ul class="example-animate-container">
24406           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
24407             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
24408           </li>
24409           <li class="animate-repeat" ng-if="results.length == 0">
24410             <strong>No results found...</strong>
24411           </li>
24412         </ul>
24413       </div>
24414     </file>
24415     <file name="animations.css">
24416       .example-animate-container {
24417         background:white;
24418         border:1px solid black;
24419         list-style:none;
24420         margin:0;
24421         padding:0 10px;
24422       }
24423
24424       .animate-repeat {
24425         line-height:40px;
24426         list-style:none;
24427         box-sizing:border-box;
24428       }
24429
24430       .animate-repeat.ng-move,
24431       .animate-repeat.ng-enter,
24432       .animate-repeat.ng-leave {
24433         -webkit-transition:all linear 0.5s;
24434         transition:all linear 0.5s;
24435       }
24436
24437       .animate-repeat.ng-leave.ng-leave-active,
24438       .animate-repeat.ng-move,
24439       .animate-repeat.ng-enter {
24440         opacity:0;
24441         max-height:0;
24442       }
24443
24444       .animate-repeat.ng-leave,
24445       .animate-repeat.ng-move.ng-move-active,
24446       .animate-repeat.ng-enter.ng-enter-active {
24447         opacity:1;
24448         max-height:40px;
24449       }
24450     </file>
24451     <file name="protractor.js" type="protractor">
24452       var friends = element.all(by.repeater('friend in friends'));
24453
24454       it('should render initial data set', function() {
24455         expect(friends.count()).toBe(10);
24456         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
24457         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
24458         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
24459         expect(element(by.binding('friends.length')).getText())
24460             .toMatch("I have 10 friends. They are:");
24461       });
24462
24463        it('should update repeater when filter predicate changes', function() {
24464          expect(friends.count()).toBe(10);
24465
24466          element(by.model('q')).sendKeys('ma');
24467
24468          expect(friends.count()).toBe(2);
24469          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
24470          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
24471        });
24472       </file>
24473     </example>
24474  */
24475 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
24476   var NG_REMOVED = '$$NG_REMOVED';
24477   var ngRepeatMinErr = minErr('ngRepeat');
24478
24479   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
24480     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
24481     scope[valueIdentifier] = value;
24482     if (keyIdentifier) scope[keyIdentifier] = key;
24483     scope.$index = index;
24484     scope.$first = (index === 0);
24485     scope.$last = (index === (arrayLength - 1));
24486     scope.$middle = !(scope.$first || scope.$last);
24487     // jshint bitwise: false
24488     scope.$odd = !(scope.$even = (index&1) === 0);
24489     // jshint bitwise: true
24490   };
24491
24492   var getBlockStart = function(block) {
24493     return block.clone[0];
24494   };
24495
24496   var getBlockEnd = function(block) {
24497     return block.clone[block.clone.length - 1];
24498   };
24499
24500
24501   return {
24502     restrict: 'A',
24503     multiElement: true,
24504     transclude: 'element',
24505     priority: 1000,
24506     terminal: true,
24507     $$tlb: true,
24508     compile: function ngRepeatCompile($element, $attr) {
24509       var expression = $attr.ngRepeat;
24510       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
24511
24512       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*$/);
24513
24514       if (!match) {
24515         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
24516             expression);
24517       }
24518
24519       var lhs = match[1];
24520       var rhs = match[2];
24521       var aliasAs = match[3];
24522       var trackByExp = match[4];
24523
24524       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
24525
24526       if (!match) {
24527         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
24528             lhs);
24529       }
24530       var valueIdentifier = match[3] || match[1];
24531       var keyIdentifier = match[2];
24532
24533       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
24534           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
24535         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
24536           aliasAs);
24537       }
24538
24539       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
24540       var hashFnLocals = {$id: hashKey};
24541
24542       if (trackByExp) {
24543         trackByExpGetter = $parse(trackByExp);
24544       } else {
24545         trackByIdArrayFn = function(key, value) {
24546           return hashKey(value);
24547         };
24548         trackByIdObjFn = function(key) {
24549           return key;
24550         };
24551       }
24552
24553       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
24554
24555         if (trackByExpGetter) {
24556           trackByIdExpFn = function(key, value, index) {
24557             // assign key, value, and $index to the locals so that they can be used in hash functions
24558             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
24559             hashFnLocals[valueIdentifier] = value;
24560             hashFnLocals.$index = index;
24561             return trackByExpGetter($scope, hashFnLocals);
24562           };
24563         }
24564
24565         // Store a list of elements from previous run. This is a hash where key is the item from the
24566         // iterator, and the value is objects with following properties.
24567         //   - scope: bound scope
24568         //   - element: previous element.
24569         //   - index: position
24570         //
24571         // We are using no-proto object so that we don't need to guard against inherited props via
24572         // hasOwnProperty.
24573         var lastBlockMap = createMap();
24574
24575         //watch props
24576         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
24577           var index, length,
24578               previousNode = $element[0],     // node that cloned nodes should be inserted after
24579                                               // initialized to the comment node anchor
24580               nextNode,
24581               // Same as lastBlockMap but it has the current state. It will become the
24582               // lastBlockMap on the next iteration.
24583               nextBlockMap = createMap(),
24584               collectionLength,
24585               key, value, // key/value of iteration
24586               trackById,
24587               trackByIdFn,
24588               collectionKeys,
24589               block,       // last object information {scope, element, id}
24590               nextBlockOrder,
24591               elementsToRemove;
24592
24593           if (aliasAs) {
24594             $scope[aliasAs] = collection;
24595           }
24596
24597           if (isArrayLike(collection)) {
24598             collectionKeys = collection;
24599             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
24600           } else {
24601             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
24602             // if object, extract keys, sort them and use to determine order of iteration over obj props
24603             collectionKeys = [];
24604             for (var itemKey in collection) {
24605               if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
24606                 collectionKeys.push(itemKey);
24607               }
24608             }
24609             collectionKeys.sort();
24610           }
24611
24612           collectionLength = collectionKeys.length;
24613           nextBlockOrder = new Array(collectionLength);
24614
24615           // locate existing items
24616           for (index = 0; index < collectionLength; index++) {
24617             key = (collection === collectionKeys) ? index : collectionKeys[index];
24618             value = collection[key];
24619             trackById = trackByIdFn(key, value, index);
24620             if (lastBlockMap[trackById]) {
24621               // found previously seen block
24622               block = lastBlockMap[trackById];
24623               delete lastBlockMap[trackById];
24624               nextBlockMap[trackById] = block;
24625               nextBlockOrder[index] = block;
24626             } else if (nextBlockMap[trackById]) {
24627               // if collision detected. restore lastBlockMap and throw an error
24628               forEach(nextBlockOrder, function(block) {
24629                 if (block && block.scope) lastBlockMap[block.id] = block;
24630               });
24631               throw ngRepeatMinErr('dupes',
24632                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
24633                   expression, trackById, value);
24634             } else {
24635               // new never before seen block
24636               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
24637               nextBlockMap[trackById] = true;
24638             }
24639           }
24640
24641           // remove leftover items
24642           for (var blockKey in lastBlockMap) {
24643             block = lastBlockMap[blockKey];
24644             elementsToRemove = getBlockNodes(block.clone);
24645             $animate.leave(elementsToRemove);
24646             if (elementsToRemove[0].parentNode) {
24647               // if the element was not removed yet because of pending animation, mark it as deleted
24648               // so that we can ignore it later
24649               for (index = 0, length = elementsToRemove.length; index < length; index++) {
24650                 elementsToRemove[index][NG_REMOVED] = true;
24651               }
24652             }
24653             block.scope.$destroy();
24654           }
24655
24656           // we are not using forEach for perf reasons (trying to avoid #call)
24657           for (index = 0; index < collectionLength; index++) {
24658             key = (collection === collectionKeys) ? index : collectionKeys[index];
24659             value = collection[key];
24660             block = nextBlockOrder[index];
24661
24662             if (block.scope) {
24663               // if we have already seen this object, then we need to reuse the
24664               // associated scope/element
24665
24666               nextNode = previousNode;
24667
24668               // skip nodes that are already pending removal via leave animation
24669               do {
24670                 nextNode = nextNode.nextSibling;
24671               } while (nextNode && nextNode[NG_REMOVED]);
24672
24673               if (getBlockStart(block) != nextNode) {
24674                 // existing item which got moved
24675                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
24676               }
24677               previousNode = getBlockEnd(block);
24678               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24679             } else {
24680               // new item which we don't know about
24681               $transclude(function ngRepeatTransclude(clone, scope) {
24682                 block.scope = scope;
24683                 // http://jsperf.com/clone-vs-createcomment
24684                 var endNode = ngRepeatEndComment.cloneNode(false);
24685                 clone[clone.length++] = endNode;
24686
24687                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
24688                 $animate.enter(clone, null, jqLite(previousNode));
24689                 previousNode = endNode;
24690                 // Note: We only need the first/last node of the cloned nodes.
24691                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24692                 // by a directive with templateUrl when its template arrives.
24693                 block.clone = clone;
24694                 nextBlockMap[block.id] = block;
24695                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24696               });
24697             }
24698           }
24699           lastBlockMap = nextBlockMap;
24700         });
24701       };
24702     }
24703   };
24704 }];
24705
24706 var NG_HIDE_CLASS = 'ng-hide';
24707 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24708 /**
24709  * @ngdoc directive
24710  * @name ngShow
24711  *
24712  * @description
24713  * The `ngShow` directive shows or hides the given HTML element based on the expression
24714  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
24715  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
24716  * in AngularJS and sets the display style to none (using an !important flag).
24717  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
24718  *
24719  * ```html
24720  * <!-- when $scope.myValue is truthy (element is visible) -->
24721  * <div ng-show="myValue"></div>
24722  *
24723  * <!-- when $scope.myValue is falsy (element is hidden) -->
24724  * <div ng-show="myValue" class="ng-hide"></div>
24725  * ```
24726  *
24727  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
24728  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
24729  * from the element causing the element not to appear hidden.
24730  *
24731  * ## Why is !important used?
24732  *
24733  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
24734  * can be easily overridden by heavier selectors. For example, something as simple
24735  * as changing the display style on a HTML list item would make hidden elements appear visible.
24736  * This also becomes a bigger issue when dealing with CSS frameworks.
24737  *
24738  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
24739  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
24740  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
24741  *
24742  * ### Overriding `.ng-hide`
24743  *
24744  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24745  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24746  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
24747  * with extra animation classes that can be added.
24748  *
24749  * ```css
24750  * .ng-hide:not(.ng-hide-animate) {
24751  *   /&#42; this is just another form of hiding an element &#42;/
24752  *   display: block!important;
24753  *   position: absolute;
24754  *   top: -9999px;
24755  *   left: -9999px;
24756  * }
24757  * ```
24758  *
24759  * By default you don't need to override in CSS anything and the animations will work around the display style.
24760  *
24761  * ## A note about animations with `ngShow`
24762  *
24763  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
24764  * is true and false. This system works like the animation system present with ngClass except that
24765  * you must also include the !important flag to override the display property
24766  * so that you can perform an animation when the element is hidden during the time of the animation.
24767  *
24768  * ```css
24769  * //
24770  * //a working example can be found at the bottom of this page
24771  * //
24772  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24773  *   /&#42; this is required as of 1.3x to properly
24774  *      apply all styling in a show/hide animation &#42;/
24775  *   transition: 0s linear all;
24776  * }
24777  *
24778  * .my-element.ng-hide-add-active,
24779  * .my-element.ng-hide-remove-active {
24780  *   /&#42; the transition is defined in the active class &#42;/
24781  *   transition: 1s linear all;
24782  * }
24783  *
24784  * .my-element.ng-hide-add { ... }
24785  * .my-element.ng-hide-add.ng-hide-add-active { ... }
24786  * .my-element.ng-hide-remove { ... }
24787  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
24788  * ```
24789  *
24790  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
24791  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
24792  *
24793  * @animations
24794  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
24795  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
24796  *
24797  * @element ANY
24798  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
24799  *     then the element is shown or hidden respectively.
24800  *
24801  * @example
24802   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24803     <file name="index.html">
24804       Click me: <input type="checkbox" ng-model="checked"><br/>
24805       <div>
24806         Show:
24807         <div class="check-element animate-show" ng-show="checked">
24808           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
24809         </div>
24810       </div>
24811       <div>
24812         Hide:
24813         <div class="check-element animate-show" ng-hide="checked">
24814           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
24815         </div>
24816       </div>
24817     </file>
24818     <file name="glyphicons.css">
24819       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
24820     </file>
24821     <file name="animations.css">
24822       .animate-show {
24823         line-height: 20px;
24824         opacity: 1;
24825         padding: 10px;
24826         border: 1px solid black;
24827         background: white;
24828       }
24829
24830       .animate-show.ng-hide-add.ng-hide-add-active,
24831       .animate-show.ng-hide-remove.ng-hide-remove-active {
24832         -webkit-transition: all linear 0.5s;
24833         transition: all linear 0.5s;
24834       }
24835
24836       .animate-show.ng-hide {
24837         line-height: 0;
24838         opacity: 0;
24839         padding: 0 10px;
24840       }
24841
24842       .check-element {
24843         padding: 10px;
24844         border: 1px solid black;
24845         background: white;
24846       }
24847     </file>
24848     <file name="protractor.js" type="protractor">
24849       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
24850       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
24851
24852       it('should check ng-show / ng-hide', function() {
24853         expect(thumbsUp.isDisplayed()).toBeFalsy();
24854         expect(thumbsDown.isDisplayed()).toBeTruthy();
24855
24856         element(by.model('checked')).click();
24857
24858         expect(thumbsUp.isDisplayed()).toBeTruthy();
24859         expect(thumbsDown.isDisplayed()).toBeFalsy();
24860       });
24861     </file>
24862   </example>
24863  */
24864 var ngShowDirective = ['$animate', function($animate) {
24865   return {
24866     restrict: 'A',
24867     multiElement: true,
24868     link: function(scope, element, attr) {
24869       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
24870         // we're adding a temporary, animation-specific class for ng-hide since this way
24871         // we can control when the element is actually displayed on screen without having
24872         // to have a global/greedy CSS selector that breaks when other animations are run.
24873         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
24874         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
24875           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
24876         });
24877       });
24878     }
24879   };
24880 }];
24881
24882
24883 /**
24884  * @ngdoc directive
24885  * @name ngHide
24886  *
24887  * @description
24888  * The `ngHide` directive shows or hides the given HTML element based on the expression
24889  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
24890  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
24891  * in AngularJS and sets the display style to none (using an !important flag).
24892  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
24893  *
24894  * ```html
24895  * <!-- when $scope.myValue is truthy (element is hidden) -->
24896  * <div ng-hide="myValue" class="ng-hide"></div>
24897  *
24898  * <!-- when $scope.myValue is falsy (element is visible) -->
24899  * <div ng-hide="myValue"></div>
24900  * ```
24901  *
24902  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
24903  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
24904  * from the element causing the element not to appear hidden.
24905  *
24906  * ## Why is !important used?
24907  *
24908  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
24909  * can be easily overridden by heavier selectors. For example, something as simple
24910  * as changing the display style on a HTML list item would make hidden elements appear visible.
24911  * This also becomes a bigger issue when dealing with CSS frameworks.
24912  *
24913  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
24914  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
24915  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
24916  *
24917  * ### Overriding `.ng-hide`
24918  *
24919  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24920  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24921  * class in CSS:
24922  *
24923  * ```css
24924  * .ng-hide {
24925  *   /&#42; this is just another form of hiding an element &#42;/
24926  *   display: block!important;
24927  *   position: absolute;
24928  *   top: -9999px;
24929  *   left: -9999px;
24930  * }
24931  * ```
24932  *
24933  * By default you don't need to override in CSS anything and the animations will work around the display style.
24934  *
24935  * ## A note about animations with `ngHide`
24936  *
24937  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
24938  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
24939  * CSS class is added and removed for you instead of your own CSS class.
24940  *
24941  * ```css
24942  * //
24943  * //a working example can be found at the bottom of this page
24944  * //
24945  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24946  *   transition: 0.5s linear all;
24947  * }
24948  *
24949  * .my-element.ng-hide-add { ... }
24950  * .my-element.ng-hide-add.ng-hide-add-active { ... }
24951  * .my-element.ng-hide-remove { ... }
24952  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
24953  * ```
24954  *
24955  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
24956  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
24957  *
24958  * @animations
24959  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
24960  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
24961  *
24962  * @element ANY
24963  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
24964  *     the element is shown or hidden respectively.
24965  *
24966  * @example
24967   <example module="ngAnimate" deps="angular-animate.js" animations="true">
24968     <file name="index.html">
24969       Click me: <input type="checkbox" ng-model="checked"><br/>
24970       <div>
24971         Show:
24972         <div class="check-element animate-hide" ng-show="checked">
24973           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
24974         </div>
24975       </div>
24976       <div>
24977         Hide:
24978         <div class="check-element animate-hide" ng-hide="checked">
24979           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
24980         </div>
24981       </div>
24982     </file>
24983     <file name="glyphicons.css">
24984       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
24985     </file>
24986     <file name="animations.css">
24987       .animate-hide {
24988         -webkit-transition: all linear 0.5s;
24989         transition: all linear 0.5s;
24990         line-height: 20px;
24991         opacity: 1;
24992         padding: 10px;
24993         border: 1px solid black;
24994         background: white;
24995       }
24996
24997       .animate-hide.ng-hide {
24998         line-height: 0;
24999         opacity: 0;
25000         padding: 0 10px;
25001       }
25002
25003       .check-element {
25004         padding: 10px;
25005         border: 1px solid black;
25006         background: white;
25007       }
25008     </file>
25009     <file name="protractor.js" type="protractor">
25010       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
25011       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
25012
25013       it('should check ng-show / ng-hide', function() {
25014         expect(thumbsUp.isDisplayed()).toBeFalsy();
25015         expect(thumbsDown.isDisplayed()).toBeTruthy();
25016
25017         element(by.model('checked')).click();
25018
25019         expect(thumbsUp.isDisplayed()).toBeTruthy();
25020         expect(thumbsDown.isDisplayed()).toBeFalsy();
25021       });
25022     </file>
25023   </example>
25024  */
25025 var ngHideDirective = ['$animate', function($animate) {
25026   return {
25027     restrict: 'A',
25028     multiElement: true,
25029     link: function(scope, element, attr) {
25030       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
25031         // The comment inside of the ngShowDirective explains why we add and
25032         // remove a temporary class for the show/hide animation
25033         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
25034           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
25035         });
25036       });
25037     }
25038   };
25039 }];
25040
25041 /**
25042  * @ngdoc directive
25043  * @name ngStyle
25044  * @restrict AC
25045  *
25046  * @description
25047  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
25048  *
25049  * @element ANY
25050  * @param {expression} ngStyle
25051  *
25052  * {@link guide/expression Expression} which evals to an
25053  * object whose keys are CSS style names and values are corresponding values for those CSS
25054  * keys.
25055  *
25056  * Since some CSS style names are not valid keys for an object, they must be quoted.
25057  * See the 'background-color' style in the example below.
25058  *
25059  * @example
25060    <example>
25061      <file name="index.html">
25062         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
25063         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
25064         <input type="button" value="clear" ng-click="myStyle={}">
25065         <br/>
25066         <span ng-style="myStyle">Sample Text</span>
25067         <pre>myStyle={{myStyle}}</pre>
25068      </file>
25069      <file name="style.css">
25070        span {
25071          color: black;
25072        }
25073      </file>
25074      <file name="protractor.js" type="protractor">
25075        var colorSpan = element(by.css('span'));
25076
25077        it('should check ng-style', function() {
25078          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
25079          element(by.css('input[value=\'set color\']')).click();
25080          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
25081          element(by.css('input[value=clear]')).click();
25082          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
25083        });
25084      </file>
25085    </example>
25086  */
25087 var ngStyleDirective = ngDirective(function(scope, element, attr) {
25088   scope.$watchCollection(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
25089     if (oldStyles && (newStyles !== oldStyles)) {
25090       forEach(oldStyles, function(val, style) { element.css(style, '');});
25091     }
25092     if (newStyles) element.css(newStyles);
25093   });
25094 });
25095
25096 /**
25097  * @ngdoc directive
25098  * @name ngSwitch
25099  * @restrict EA
25100  *
25101  * @description
25102  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
25103  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
25104  * as specified in the template.
25105  *
25106  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
25107  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
25108  * matches the value obtained from the evaluated expression. In other words, you define a container element
25109  * (where you place the directive), place an expression on the **`on="..."` attribute**
25110  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
25111  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
25112  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
25113  * attribute is displayed.
25114  *
25115  * <div class="alert alert-info">
25116  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
25117  * as literal string values to match against.
25118  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
25119  * value of the expression `$scope.someVal`.
25120  * </div>
25121
25122  * @animations
25123  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
25124  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
25125  *
25126  * @usage
25127  *
25128  * ```
25129  * <ANY ng-switch="expression">
25130  *   <ANY ng-switch-when="matchValue1">...</ANY>
25131  *   <ANY ng-switch-when="matchValue2">...</ANY>
25132  *   <ANY ng-switch-default>...</ANY>
25133  * </ANY>
25134  * ```
25135  *
25136  *
25137  * @scope
25138  * @priority 1200
25139  * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
25140  * On child elements add:
25141  *
25142  * * `ngSwitchWhen`: the case statement to match against. If match then this
25143  *   case will be displayed. If the same match appears multiple times, all the
25144  *   elements will be displayed.
25145  * * `ngSwitchDefault`: the default case when no other case match. If there
25146  *   are multiple default cases, all of them will be displayed when no other
25147  *   case match.
25148  *
25149  *
25150  * @example
25151   <example module="switchExample" deps="angular-animate.js" animations="true">
25152     <file name="index.html">
25153       <div ng-controller="ExampleController">
25154         <select ng-model="selection" ng-options="item for item in items">
25155         </select>
25156         <tt>selection={{selection}}</tt>
25157         <hr/>
25158         <div class="animate-switch-container"
25159           ng-switch on="selection">
25160             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
25161             <div class="animate-switch" ng-switch-when="home">Home Span</div>
25162             <div class="animate-switch" ng-switch-default>default</div>
25163         </div>
25164       </div>
25165     </file>
25166     <file name="script.js">
25167       angular.module('switchExample', ['ngAnimate'])
25168         .controller('ExampleController', ['$scope', function($scope) {
25169           $scope.items = ['settings', 'home', 'other'];
25170           $scope.selection = $scope.items[0];
25171         }]);
25172     </file>
25173     <file name="animations.css">
25174       .animate-switch-container {
25175         position:relative;
25176         background:white;
25177         border:1px solid black;
25178         height:40px;
25179         overflow:hidden;
25180       }
25181
25182       .animate-switch {
25183         padding:10px;
25184       }
25185
25186       .animate-switch.ng-animate {
25187         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25188         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25189
25190         position:absolute;
25191         top:0;
25192         left:0;
25193         right:0;
25194         bottom:0;
25195       }
25196
25197       .animate-switch.ng-leave.ng-leave-active,
25198       .animate-switch.ng-enter {
25199         top:-50px;
25200       }
25201       .animate-switch.ng-leave,
25202       .animate-switch.ng-enter.ng-enter-active {
25203         top:0;
25204       }
25205     </file>
25206     <file name="protractor.js" type="protractor">
25207       var switchElem = element(by.css('[ng-switch]'));
25208       var select = element(by.model('selection'));
25209
25210       it('should start in settings', function() {
25211         expect(switchElem.getText()).toMatch(/Settings Div/);
25212       });
25213       it('should change to home', function() {
25214         select.all(by.css('option')).get(1).click();
25215         expect(switchElem.getText()).toMatch(/Home Span/);
25216       });
25217       it('should select default', function() {
25218         select.all(by.css('option')).get(2).click();
25219         expect(switchElem.getText()).toMatch(/default/);
25220       });
25221     </file>
25222   </example>
25223  */
25224 var ngSwitchDirective = ['$animate', function($animate) {
25225   return {
25226     restrict: 'EA',
25227     require: 'ngSwitch',
25228
25229     // asks for $scope to fool the BC controller module
25230     controller: ['$scope', function ngSwitchController() {
25231      this.cases = {};
25232     }],
25233     link: function(scope, element, attr, ngSwitchController) {
25234       var watchExpr = attr.ngSwitch || attr.on,
25235           selectedTranscludes = [],
25236           selectedElements = [],
25237           previousLeaveAnimations = [],
25238           selectedScopes = [];
25239
25240       var spliceFactory = function(array, index) {
25241           return function() { array.splice(index, 1); };
25242       };
25243
25244       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
25245         var i, ii;
25246         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
25247           $animate.cancel(previousLeaveAnimations[i]);
25248         }
25249         previousLeaveAnimations.length = 0;
25250
25251         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
25252           var selected = getBlockNodes(selectedElements[i].clone);
25253           selectedScopes[i].$destroy();
25254           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
25255           promise.then(spliceFactory(previousLeaveAnimations, i));
25256         }
25257
25258         selectedElements.length = 0;
25259         selectedScopes.length = 0;
25260
25261         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
25262           forEach(selectedTranscludes, function(selectedTransclude) {
25263             selectedTransclude.transclude(function(caseElement, selectedScope) {
25264               selectedScopes.push(selectedScope);
25265               var anchor = selectedTransclude.element;
25266               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
25267               var block = { clone: caseElement };
25268
25269               selectedElements.push(block);
25270               $animate.enter(caseElement, anchor.parent(), anchor);
25271             });
25272           });
25273         }
25274       });
25275     }
25276   };
25277 }];
25278
25279 var ngSwitchWhenDirective = ngDirective({
25280   transclude: 'element',
25281   priority: 1200,
25282   require: '^ngSwitch',
25283   multiElement: true,
25284   link: function(scope, element, attrs, ctrl, $transclude) {
25285     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
25286     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
25287   }
25288 });
25289
25290 var ngSwitchDefaultDirective = ngDirective({
25291   transclude: 'element',
25292   priority: 1200,
25293   require: '^ngSwitch',
25294   multiElement: true,
25295   link: function(scope, element, attr, ctrl, $transclude) {
25296     ctrl.cases['?'] = (ctrl.cases['?'] || []);
25297     ctrl.cases['?'].push({ transclude: $transclude, element: element });
25298    }
25299 });
25300
25301 /**
25302  * @ngdoc directive
25303  * @name ngTransclude
25304  * @restrict EAC
25305  *
25306  * @description
25307  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
25308  *
25309  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
25310  *
25311  * @element ANY
25312  *
25313  * @example
25314    <example module="transcludeExample">
25315      <file name="index.html">
25316        <script>
25317          angular.module('transcludeExample', [])
25318           .directive('pane', function(){
25319              return {
25320                restrict: 'E',
25321                transclude: true,
25322                scope: { title:'@' },
25323                template: '<div style="border: 1px solid black;">' +
25324                            '<div style="background-color: gray">{{title}}</div>' +
25325                            '<ng-transclude></ng-transclude>' +
25326                          '</div>'
25327              };
25328          })
25329          .controller('ExampleController', ['$scope', function($scope) {
25330            $scope.title = 'Lorem Ipsum';
25331            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
25332          }]);
25333        </script>
25334        <div ng-controller="ExampleController">
25335          <input ng-model="title"> <br/>
25336          <textarea ng-model="text"></textarea> <br/>
25337          <pane title="{{title}}">{{text}}</pane>
25338        </div>
25339      </file>
25340      <file name="protractor.js" type="protractor">
25341         it('should have transcluded', function() {
25342           var titleElement = element(by.model('title'));
25343           titleElement.clear();
25344           titleElement.sendKeys('TITLE');
25345           var textElement = element(by.model('text'));
25346           textElement.clear();
25347           textElement.sendKeys('TEXT');
25348           expect(element(by.binding('title')).getText()).toEqual('TITLE');
25349           expect(element(by.binding('text')).getText()).toEqual('TEXT');
25350         });
25351      </file>
25352    </example>
25353  *
25354  */
25355 var ngTranscludeDirective = ngDirective({
25356   restrict: 'EAC',
25357   link: function($scope, $element, $attrs, controller, $transclude) {
25358     if (!$transclude) {
25359       throw minErr('ngTransclude')('orphan',
25360        'Illegal use of ngTransclude directive in the template! ' +
25361        'No parent directive that requires a transclusion found. ' +
25362        'Element: {0}',
25363        startingTag($element));
25364     }
25365
25366     $transclude(function(clone) {
25367       $element.empty();
25368       $element.append(clone);
25369     });
25370   }
25371 });
25372
25373 /**
25374  * @ngdoc directive
25375  * @name script
25376  * @restrict E
25377  *
25378  * @description
25379  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
25380  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
25381  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
25382  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
25383  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
25384  *
25385  * @param {string} type Must be set to `'text/ng-template'`.
25386  * @param {string} id Cache name of the template.
25387  *
25388  * @example
25389   <example>
25390     <file name="index.html">
25391       <script type="text/ng-template" id="/tpl.html">
25392         Content of the template.
25393       </script>
25394
25395       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
25396       <div id="tpl-content" ng-include src="currentTpl"></div>
25397     </file>
25398     <file name="protractor.js" type="protractor">
25399       it('should load template defined inside script tag', function() {
25400         element(by.css('#tpl-link')).click();
25401         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
25402       });
25403     </file>
25404   </example>
25405  */
25406 var scriptDirective = ['$templateCache', function($templateCache) {
25407   return {
25408     restrict: 'E',
25409     terminal: true,
25410     compile: function(element, attr) {
25411       if (attr.type == 'text/ng-template') {
25412         var templateUrl = attr.id,
25413             text = element[0].text;
25414
25415         $templateCache.put(templateUrl, text);
25416       }
25417     }
25418   };
25419 }];
25420
25421 var ngOptionsMinErr = minErr('ngOptions');
25422 /**
25423  * @ngdoc directive
25424  * @name select
25425  * @restrict E
25426  *
25427  * @description
25428  * HTML `SELECT` element with angular data-binding.
25429  *
25430  * # `ngOptions`
25431  *
25432  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
25433  * elements for the `<select>` element using the array or object obtained by evaluating the
25434  * `ngOptions` comprehension expression.
25435  *
25436  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
25437  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
25438  * increasing speed by not creating a new scope for each repeated instance, as well as providing
25439  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
25440  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
25441  *  to a non-string value. This is because an option element can only be bound to string values at
25442  * present.
25443  *
25444  * When an item in the `<select>` menu is selected, the array element or object property
25445  * represented by the selected option will be bound to the model identified by the `ngModel`
25446  * directive.
25447  *
25448  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
25449  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
25450  * option. See example below for demonstration.
25451  *
25452  * <div class="alert alert-warning">
25453  * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
25454  * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
25455  * </div>
25456  *
25457  * ## `select` **`as`**
25458  *
25459  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
25460  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
25461  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
25462  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
25463  *
25464  *
25465  * ### `select` **`as`** and **`track by`**
25466  *
25467  * <div class="alert alert-warning">
25468  * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
25469  * </div>
25470  *
25471  * Consider the following example:
25472  *
25473  * ```html
25474  * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
25475  * ```
25476  *
25477  * ```js
25478  * $scope.values = [{
25479  *   id: 1,
25480  *   label: 'aLabel',
25481  *   subItem: { name: 'aSubItem' }
25482  * }, {
25483  *   id: 2,
25484  *   label: 'bLabel',
25485  *   subItem: { name: 'bSubItem' }
25486  * }];
25487  *
25488  * $scope.selected = { name: 'aSubItem' };
25489  * ```
25490  *
25491  * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
25492  * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
25493  * following:
25494  *
25495  * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
25496  * 2. Apply **`track by`** to the already selected value in `ngModel`.
25497  *    In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
25498  *    value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
25499  *    a wrong object, the selected element can't be found, `<select>` is always reset to the "not
25500  *    selected" option.
25501  *
25502  *
25503  * @param {string} ngModel Assignable angular expression to data-bind to.
25504  * @param {string=} name Property name of the form under which the control is published.
25505  * @param {string=} required The control is considered valid only if value is entered.
25506  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25507  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25508  *    `required` when you want to data-bind to the `required` attribute.
25509  * @param {comprehension_expression=} ngOptions in one of the following forms:
25510  *
25511  *   * for array data sources:
25512  *     * `label` **`for`** `value` **`in`** `array`
25513  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
25514  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25515  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25516  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
25517  *        (for including a filter with `track by`)
25518  *   * for object data sources:
25519  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25520  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25521  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
25522  *     * `select` **`as`** `label` **`group by`** `group`
25523  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
25524  *
25525  * Where:
25526  *
25527  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
25528  *   * `value`: local variable which will refer to each item in the `array` or each property value
25529  *      of `object` during iteration.
25530  *   * `key`: local variable which will refer to a property name in `object` during iteration.
25531  *   * `label`: The result of this expression will be the label for `<option>` element. The
25532  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
25533  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
25534  *      element. If not specified, `select` expression will default to `value`.
25535  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
25536  *      DOM element.
25537  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
25538  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
25539  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
25540  *      even when the options are recreated (e.g. reloaded from the server).
25541  *
25542  * @example
25543     <example module="selectExample">
25544       <file name="index.html">
25545         <script>
25546         angular.module('selectExample', [])
25547           .controller('ExampleController', ['$scope', function($scope) {
25548             $scope.colors = [
25549               {name:'black', shade:'dark'},
25550               {name:'white', shade:'light'},
25551               {name:'red', shade:'dark'},
25552               {name:'blue', shade:'dark'},
25553               {name:'yellow', shade:'light'}
25554             ];
25555             $scope.myColor = $scope.colors[2]; // red
25556           }]);
25557         </script>
25558         <div ng-controller="ExampleController">
25559           <ul>
25560             <li ng-repeat="color in colors">
25561               Name: <input ng-model="color.name">
25562               [<a href ng-click="colors.splice($index, 1)">X</a>]
25563             </li>
25564             <li>
25565               [<a href ng-click="colors.push({})">add</a>]
25566             </li>
25567           </ul>
25568           <hr/>
25569           Color (null not allowed):
25570           <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
25571
25572           Color (null allowed):
25573           <span  class="nullable">
25574             <select ng-model="myColor" ng-options="color.name for color in colors">
25575               <option value="">-- choose color --</option>
25576             </select>
25577           </span><br/>
25578
25579           Color grouped by shade:
25580           <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
25581           </select><br/>
25582
25583
25584           Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
25585           <hr/>
25586           Currently selected: {{ {selected_color:myColor} }}
25587           <div style="border:solid 1px black; height:20px"
25588                ng-style="{'background-color':myColor.name}">
25589           </div>
25590         </div>
25591       </file>
25592       <file name="protractor.js" type="protractor">
25593          it('should check ng-options', function() {
25594            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
25595            element.all(by.model('myColor')).first().click();
25596            element.all(by.css('select[ng-model="myColor"] option')).first().click();
25597            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
25598            element(by.css('.nullable select[ng-model="myColor"]')).click();
25599            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
25600            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
25601          });
25602       </file>
25603     </example>
25604  */
25605
25606 var ngOptionsDirective = valueFn({
25607   restrict: 'A',
25608   terminal: true
25609 });
25610
25611 // jshint maxlen: false
25612 var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
25613                          //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
25614   var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
25615       nullModelCtrl = {$setViewValue: noop};
25616 // jshint maxlen: 100
25617
25618   return {
25619     restrict: 'E',
25620     require: ['select', '?ngModel'],
25621     controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
25622       var self = this,
25623           optionsMap = {},
25624           ngModelCtrl = nullModelCtrl,
25625           nullOption,
25626           unknownOption;
25627
25628
25629       self.databound = $attrs.ngModel;
25630
25631
25632       self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
25633         ngModelCtrl = ngModelCtrl_;
25634         nullOption = nullOption_;
25635         unknownOption = unknownOption_;
25636       };
25637
25638
25639       self.addOption = function(value, element) {
25640         assertNotHasOwnProperty(value, '"option value"');
25641         optionsMap[value] = true;
25642
25643         if (ngModelCtrl.$viewValue == value) {
25644           $element.val(value);
25645           if (unknownOption.parent()) unknownOption.remove();
25646         }
25647         // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
25648         // Adding an <option selected="selected"> element to a <select required="required"> should
25649         // automatically select the new element
25650         if (element && element[0].hasAttribute('selected')) {
25651           element[0].selected = true;
25652         }
25653       };
25654
25655
25656       self.removeOption = function(value) {
25657         if (this.hasOption(value)) {
25658           delete optionsMap[value];
25659           if (ngModelCtrl.$viewValue === value) {
25660             this.renderUnknownOption(value);
25661           }
25662         }
25663       };
25664
25665
25666       self.renderUnknownOption = function(val) {
25667         var unknownVal = '? ' + hashKey(val) + ' ?';
25668         unknownOption.val(unknownVal);
25669         $element.prepend(unknownOption);
25670         $element.val(unknownVal);
25671         unknownOption.prop('selected', true); // needed for IE
25672       };
25673
25674
25675       self.hasOption = function(value) {
25676         return optionsMap.hasOwnProperty(value);
25677       };
25678
25679       $scope.$on('$destroy', function() {
25680         // disable unknown option so that we don't do work when the whole select is being destroyed
25681         self.renderUnknownOption = noop;
25682       });
25683     }],
25684
25685     link: function(scope, element, attr, ctrls) {
25686       // if ngModel is not defined, we don't need to do anything
25687       if (!ctrls[1]) return;
25688
25689       var selectCtrl = ctrls[0],
25690           ngModelCtrl = ctrls[1],
25691           multiple = attr.multiple,
25692           optionsExp = attr.ngOptions,
25693           nullOption = false, // if false, user will not be able to select it (used by ngOptions)
25694           emptyOption,
25695           renderScheduled = false,
25696           // we can't just jqLite('<option>') since jqLite is not smart enough
25697           // to create it in <select> and IE barfs otherwise.
25698           optionTemplate = jqLite(document.createElement('option')),
25699           optGroupTemplate =jqLite(document.createElement('optgroup')),
25700           unknownOption = optionTemplate.clone();
25701
25702       // find "null" option
25703       for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
25704         if (children[i].value === '') {
25705           emptyOption = nullOption = children.eq(i);
25706           break;
25707         }
25708       }
25709
25710       selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
25711
25712       // required validator
25713       if (multiple) {
25714         ngModelCtrl.$isEmpty = function(value) {
25715           return !value || value.length === 0;
25716         };
25717       }
25718
25719       if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
25720       else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
25721       else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
25722
25723
25724       ////////////////////////////
25725
25726
25727
25728       function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
25729         ngModelCtrl.$render = function() {
25730           var viewValue = ngModelCtrl.$viewValue;
25731
25732           if (selectCtrl.hasOption(viewValue)) {
25733             if (unknownOption.parent()) unknownOption.remove();
25734             selectElement.val(viewValue);
25735             if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
25736           } else {
25737             if (isUndefined(viewValue) && emptyOption) {
25738               selectElement.val('');
25739             } else {
25740               selectCtrl.renderUnknownOption(viewValue);
25741             }
25742           }
25743         };
25744
25745         selectElement.on('change', function() {
25746           scope.$apply(function() {
25747             if (unknownOption.parent()) unknownOption.remove();
25748             ngModelCtrl.$setViewValue(selectElement.val());
25749           });
25750         });
25751       }
25752
25753       function setupAsMultiple(scope, selectElement, ctrl) {
25754         var lastView;
25755         ctrl.$render = function() {
25756           var items = new HashMap(ctrl.$viewValue);
25757           forEach(selectElement.find('option'), function(option) {
25758             option.selected = isDefined(items.get(option.value));
25759           });
25760         };
25761
25762         // we have to do it on each watch since ngModel watches reference, but
25763         // we need to work of an array, so we need to see if anything was inserted/removed
25764         scope.$watch(function selectMultipleWatch() {
25765           if (!equals(lastView, ctrl.$viewValue)) {
25766             lastView = shallowCopy(ctrl.$viewValue);
25767             ctrl.$render();
25768           }
25769         });
25770
25771         selectElement.on('change', function() {
25772           scope.$apply(function() {
25773             var array = [];
25774             forEach(selectElement.find('option'), function(option) {
25775               if (option.selected) {
25776                 array.push(option.value);
25777               }
25778             });
25779             ctrl.$setViewValue(array);
25780           });
25781         });
25782       }
25783
25784       function setupAsOptions(scope, selectElement, ctrl) {
25785         var match;
25786
25787         if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
25788           throw ngOptionsMinErr('iexp',
25789             "Expected expression in form of " +
25790             "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
25791             " but got '{0}'. Element: {1}",
25792             optionsExp, startingTag(selectElement));
25793         }
25794
25795         var displayFn = $parse(match[2] || match[1]),
25796             valueName = match[4] || match[6],
25797             selectAs = / as /.test(match[0]) && match[1],
25798             selectAsFn = selectAs ? $parse(selectAs) : null,
25799             keyName = match[5],
25800             groupByFn = $parse(match[3] || ''),
25801             valueFn = $parse(match[2] ? match[1] : valueName),
25802             valuesFn = $parse(match[7]),
25803             track = match[8],
25804             trackFn = track ? $parse(match[8]) : null,
25805             trackKeysCache = {},
25806             // This is an array of array of existing option groups in DOM.
25807             // We try to reuse these if possible
25808             // - optionGroupsCache[0] is the options with no option group
25809             // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
25810             optionGroupsCache = [[{element: selectElement, label:''}]],
25811             //re-usable object to represent option's locals
25812             locals = {};
25813
25814         if (nullOption) {
25815           // compile the element since there might be bindings in it
25816           $compile(nullOption)(scope);
25817
25818           // remove the class, which is added automatically because we recompile the element and it
25819           // becomes the compilation root
25820           nullOption.removeClass('ng-scope');
25821
25822           // we need to remove it before calling selectElement.empty() because otherwise IE will
25823           // remove the label from the element. wtf?
25824           nullOption.remove();
25825         }
25826
25827         // clear contents, we'll add what's needed based on the model
25828         selectElement.empty();
25829
25830         selectElement.on('change', selectionChanged);
25831
25832         ctrl.$render = render;
25833
25834         scope.$watchCollection(valuesFn, scheduleRendering);
25835         scope.$watchCollection(getLabels, scheduleRendering);
25836
25837         if (multiple) {
25838           scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
25839         }
25840
25841         // ------------------------------------------------------------------ //
25842
25843         function callExpression(exprFn, key, value) {
25844           locals[valueName] = value;
25845           if (keyName) locals[keyName] = key;
25846           return exprFn(scope, locals);
25847         }
25848
25849         function selectionChanged() {
25850           scope.$apply(function() {
25851             var collection = valuesFn(scope) || [];
25852             var viewValue;
25853             if (multiple) {
25854               viewValue = [];
25855               forEach(selectElement.val(), function(selectedKey) {
25856                   selectedKey = trackFn ? trackKeysCache[selectedKey] : selectedKey;
25857                 viewValue.push(getViewValue(selectedKey, collection[selectedKey]));
25858               });
25859             } else {
25860               var selectedKey = trackFn ? trackKeysCache[selectElement.val()] : selectElement.val();
25861               viewValue = getViewValue(selectedKey, collection[selectedKey]);
25862             }
25863             ctrl.$setViewValue(viewValue);
25864             render();
25865           });
25866         }
25867
25868         function getViewValue(key, value) {
25869           if (key === '?') {
25870             return undefined;
25871           } else if (key === '') {
25872             return null;
25873           } else {
25874             var viewValueFn = selectAsFn ? selectAsFn : valueFn;
25875             return callExpression(viewValueFn, key, value);
25876           }
25877         }
25878
25879         function getLabels() {
25880           var values = valuesFn(scope);
25881           var toDisplay;
25882           if (values && isArray(values)) {
25883             toDisplay = new Array(values.length);
25884             for (var i = 0, ii = values.length; i < ii; i++) {
25885               toDisplay[i] = callExpression(displayFn, i, values[i]);
25886             }
25887             return toDisplay;
25888           } else if (values) {
25889             // TODO: Add a test for this case
25890             toDisplay = {};
25891             for (var prop in values) {
25892               if (values.hasOwnProperty(prop)) {
25893                 toDisplay[prop] = callExpression(displayFn, prop, values[prop]);
25894               }
25895             }
25896           }
25897           return toDisplay;
25898         }
25899
25900         function createIsSelectedFn(viewValue) {
25901           var selectedSet;
25902           if (multiple) {
25903             if (trackFn && isArray(viewValue)) {
25904
25905               selectedSet = new HashMap([]);
25906               for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
25907                 // tracking by key
25908                 selectedSet.put(callExpression(trackFn, null, viewValue[trackIndex]), true);
25909               }
25910             } else {
25911               selectedSet = new HashMap(viewValue);
25912             }
25913           } else if (trackFn) {
25914             viewValue = callExpression(trackFn, null, viewValue);
25915           }
25916
25917           return function isSelected(key, value) {
25918             var compareValueFn;
25919             if (trackFn) {
25920               compareValueFn = trackFn;
25921             } else if (selectAsFn) {
25922               compareValueFn = selectAsFn;
25923             } else {
25924               compareValueFn = valueFn;
25925             }
25926
25927             if (multiple) {
25928               return isDefined(selectedSet.remove(callExpression(compareValueFn, key, value)));
25929             } else {
25930               return viewValue === callExpression(compareValueFn, key, value);
25931             }
25932           };
25933         }
25934
25935         function scheduleRendering() {
25936           if (!renderScheduled) {
25937             scope.$$postDigest(render);
25938             renderScheduled = true;
25939           }
25940         }
25941
25942         /**
25943          * A new labelMap is created with each render.
25944          * This function is called for each existing option with added=false,
25945          * and each new option with added=true.
25946          * - Labels that are passed to this method twice,
25947          * (once with added=true and once with added=false) will end up with a value of 0, and
25948          * will cause no change to happen to the corresponding option.
25949          * - Labels that are passed to this method only once with added=false will end up with a
25950          * value of -1 and will eventually be passed to selectCtrl.removeOption()
25951          * - Labels that are passed to this method only once with added=true will end up with a
25952          * value of 1 and will eventually be passed to selectCtrl.addOption()
25953         */
25954         function updateLabelMap(labelMap, label, added) {
25955           labelMap[label] = labelMap[label] || 0;
25956           labelMap[label] += (added ? 1 : -1);
25957         }
25958
25959         function render() {
25960           renderScheduled = false;
25961
25962           // Temporary location for the option groups before we render them
25963           var optionGroups = {'':[]},
25964               optionGroupNames = [''],
25965               optionGroupName,
25966               optionGroup,
25967               option,
25968               existingParent, existingOptions, existingOption,
25969               viewValue = ctrl.$viewValue,
25970               values = valuesFn(scope) || [],
25971               keys = keyName ? sortedKeys(values) : values,
25972               key,
25973               value,
25974               groupLength, length,
25975               groupIndex, index,
25976               labelMap = {},
25977               selected,
25978               isSelected = createIsSelectedFn(viewValue),
25979               anySelected = false,
25980               lastElement,
25981               element,
25982               label,
25983               optionId;
25984
25985           trackKeysCache = {};
25986
25987           // We now build up the list of options we need (we merge later)
25988           for (index = 0; length = keys.length, index < length; index++) {
25989             key = index;
25990             if (keyName) {
25991               key = keys[index];
25992               if (key.charAt(0) === '$') continue;
25993             }
25994             value = values[key];
25995
25996             optionGroupName = callExpression(groupByFn, key, value) || '';
25997             if (!(optionGroup = optionGroups[optionGroupName])) {
25998               optionGroup = optionGroups[optionGroupName] = [];
25999               optionGroupNames.push(optionGroupName);
26000             }
26001
26002             selected = isSelected(key, value);
26003             anySelected = anySelected || selected;
26004
26005             label = callExpression(displayFn, key, value); // what will be seen by the user
26006
26007             // doing displayFn(scope, locals) || '' overwrites zero values
26008             label = isDefined(label) ? label : '';
26009             optionId = trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index);
26010             if (trackFn) {
26011               trackKeysCache[optionId] = key;
26012             }
26013
26014             optionGroup.push({
26015               // either the index into array or key from object
26016               id: optionId,
26017               label: label,
26018               selected: selected                   // determine if we should be selected
26019             });
26020           }
26021           if (!multiple) {
26022             if (nullOption || viewValue === null) {
26023               // insert null option if we have a placeholder, or the model is null
26024               optionGroups[''].unshift({id:'', label:'', selected:!anySelected});
26025             } else if (!anySelected) {
26026               // option could not be found, we have to insert the undefined item
26027               optionGroups[''].unshift({id:'?', label:'', selected:true});
26028             }
26029           }
26030
26031           // Now we need to update the list of DOM nodes to match the optionGroups we computed above
26032           for (groupIndex = 0, groupLength = optionGroupNames.length;
26033                groupIndex < groupLength;
26034                groupIndex++) {
26035             // current option group name or '' if no group
26036             optionGroupName = optionGroupNames[groupIndex];
26037
26038             // list of options for that group. (first item has the parent)
26039             optionGroup = optionGroups[optionGroupName];
26040
26041             if (optionGroupsCache.length <= groupIndex) {
26042               // we need to grow the optionGroups
26043               existingParent = {
26044                 element: optGroupTemplate.clone().attr('label', optionGroupName),
26045                 label: optionGroup.label
26046               };
26047               existingOptions = [existingParent];
26048               optionGroupsCache.push(existingOptions);
26049               selectElement.append(existingParent.element);
26050             } else {
26051               existingOptions = optionGroupsCache[groupIndex];
26052               existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
26053
26054               // update the OPTGROUP label if not the same.
26055               if (existingParent.label != optionGroupName) {
26056                 existingParent.element.attr('label', existingParent.label = optionGroupName);
26057               }
26058             }
26059
26060             lastElement = null;  // start at the beginning
26061             for (index = 0, length = optionGroup.length; index < length; index++) {
26062               option = optionGroup[index];
26063               if ((existingOption = existingOptions[index + 1])) {
26064                 // reuse elements
26065                 lastElement = existingOption.element;
26066                 if (existingOption.label !== option.label) {
26067                   updateLabelMap(labelMap, existingOption.label, false);
26068                   updateLabelMap(labelMap, option.label, true);
26069                   lastElement.text(existingOption.label = option.label);
26070                   lastElement.prop('label', existingOption.label);
26071                 }
26072                 if (existingOption.id !== option.id) {
26073                   lastElement.val(existingOption.id = option.id);
26074                 }
26075                 // lastElement.prop('selected') provided by jQuery has side-effects
26076                 if (lastElement[0].selected !== option.selected) {
26077                   lastElement.prop('selected', (existingOption.selected = option.selected));
26078                   if (msie) {
26079                     // See #7692
26080                     // The selected item wouldn't visually update on IE without this.
26081                     // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
26082                     lastElement.prop('selected', existingOption.selected);
26083                   }
26084                 }
26085               } else {
26086                 // grow elements
26087
26088                 // if it's a null option
26089                 if (option.id === '' && nullOption) {
26090                   // put back the pre-compiled element
26091                   element = nullOption;
26092                 } else {
26093                   // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
26094                   // in this version of jQuery on some browser the .text() returns a string
26095                   // rather then the element.
26096                   (element = optionTemplate.clone())
26097                       .val(option.id)
26098                       .prop('selected', option.selected)
26099                       .attr('selected', option.selected)
26100                       .prop('label', option.label)
26101                       .text(option.label);
26102                 }
26103
26104                 existingOptions.push(existingOption = {
26105                     element: element,
26106                     label: option.label,
26107                     id: option.id,
26108                     selected: option.selected
26109                 });
26110                 updateLabelMap(labelMap, option.label, true);
26111                 if (lastElement) {
26112                   lastElement.after(element);
26113                 } else {
26114                   existingParent.element.append(element);
26115                 }
26116                 lastElement = element;
26117               }
26118             }
26119             // remove any excessive OPTIONs in a group
26120             index++; // increment since the existingOptions[0] is parent element not OPTION
26121             while (existingOptions.length > index) {
26122               option = existingOptions.pop();
26123               updateLabelMap(labelMap, option.label, false);
26124               option.element.remove();
26125             }
26126           }
26127           // remove any excessive OPTGROUPs from select
26128           while (optionGroupsCache.length > groupIndex) {
26129             // remove all the labels in the option group
26130             optionGroup = optionGroupsCache.pop();
26131             for (index = 1; index < optionGroup.length; ++index) {
26132               updateLabelMap(labelMap, optionGroup[index].label, false);
26133             }
26134             optionGroup[0].element.remove();
26135           }
26136           forEach(labelMap, function(count, label) {
26137             if (count > 0) {
26138               selectCtrl.addOption(label);
26139             } else if (count < 0) {
26140               selectCtrl.removeOption(label);
26141             }
26142           });
26143         }
26144       }
26145     }
26146   };
26147 }];
26148
26149 var optionDirective = ['$interpolate', function($interpolate) {
26150   var nullSelectCtrl = {
26151     addOption: noop,
26152     removeOption: noop
26153   };
26154
26155   return {
26156     restrict: 'E',
26157     priority: 100,
26158     compile: function(element, attr) {
26159       if (isUndefined(attr.value)) {
26160         var interpolateFn = $interpolate(element.text(), true);
26161         if (!interpolateFn) {
26162           attr.$set('value', element.text());
26163         }
26164       }
26165
26166       return function(scope, element, attr) {
26167         var selectCtrlName = '$selectController',
26168             parent = element.parent(),
26169             selectCtrl = parent.data(selectCtrlName) ||
26170               parent.parent().data(selectCtrlName); // in case we are in optgroup
26171
26172         if (!selectCtrl || !selectCtrl.databound) {
26173           selectCtrl = nullSelectCtrl;
26174         }
26175
26176         if (interpolateFn) {
26177           scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
26178             attr.$set('value', newVal);
26179             if (oldVal !== newVal) {
26180               selectCtrl.removeOption(oldVal);
26181             }
26182             selectCtrl.addOption(newVal, element);
26183           });
26184         } else {
26185           selectCtrl.addOption(attr.value, element);
26186         }
26187
26188         element.on('$destroy', function() {
26189           selectCtrl.removeOption(attr.value);
26190         });
26191       };
26192     }
26193   };
26194 }];
26195
26196 var styleDirective = valueFn({
26197   restrict: 'E',
26198   terminal: false
26199 });
26200
26201 var requiredDirective = function() {
26202   return {
26203     restrict: 'A',
26204     require: '?ngModel',
26205     link: function(scope, elm, attr, ctrl) {
26206       if (!ctrl) return;
26207       attr.required = true; // force truthy in case we are on non input element
26208
26209       ctrl.$validators.required = function(modelValue, viewValue) {
26210         return !attr.required || !ctrl.$isEmpty(viewValue);
26211       };
26212
26213       attr.$observe('required', function() {
26214         ctrl.$validate();
26215       });
26216     }
26217   };
26218 };
26219
26220
26221 var patternDirective = function() {
26222   return {
26223     restrict: 'A',
26224     require: '?ngModel',
26225     link: function(scope, elm, attr, ctrl) {
26226       if (!ctrl) return;
26227
26228       var regexp, patternExp = attr.ngPattern || attr.pattern;
26229       attr.$observe('pattern', function(regex) {
26230         if (isString(regex) && regex.length > 0) {
26231           regex = new RegExp('^' + regex + '$');
26232         }
26233
26234         if (regex && !regex.test) {
26235           throw minErr('ngPattern')('noregexp',
26236             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
26237             regex, startingTag(elm));
26238         }
26239
26240         regexp = regex || undefined;
26241         ctrl.$validate();
26242       });
26243
26244       ctrl.$validators.pattern = function(value) {
26245         return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
26246       };
26247     }
26248   };
26249 };
26250
26251
26252 var maxlengthDirective = function() {
26253   return {
26254     restrict: 'A',
26255     require: '?ngModel',
26256     link: function(scope, elm, attr, ctrl) {
26257       if (!ctrl) return;
26258
26259       var maxlength = -1;
26260       attr.$observe('maxlength', function(value) {
26261         var intVal = int(value);
26262         maxlength = isNaN(intVal) ? -1 : intVal;
26263         ctrl.$validate();
26264       });
26265       ctrl.$validators.maxlength = function(modelValue, viewValue) {
26266         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
26267       };
26268     }
26269   };
26270 };
26271
26272 var minlengthDirective = function() {
26273   return {
26274     restrict: 'A',
26275     require: '?ngModel',
26276     link: function(scope, elm, attr, ctrl) {
26277       if (!ctrl) return;
26278
26279       var minlength = 0;
26280       attr.$observe('minlength', function(value) {
26281         minlength = int(value) || 0;
26282         ctrl.$validate();
26283       });
26284       ctrl.$validators.minlength = function(modelValue, viewValue) {
26285         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
26286       };
26287     }
26288   };
26289 };
26290
26291   if (window.angular.bootstrap) {
26292     //AngularJS is already loaded, so we can return here...
26293     console.log('WARNING: Tried to load angular more than once.');
26294     return;
26295   }
26296
26297   //try to bind to jquery now so that one can write jqLite(document).ready()
26298   //but we will rebind on bootstrap again.
26299   bindJQuery();
26300
26301   publishExternalAPI(angular);
26302
26303   jqLite(document).ready(function() {
26304     angularInit(document, bootstrap);
26305   });
26306
26307 })(window, document);
26308
26309 !window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>');