Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / app / fusion / external / ebz / angular_js / angular.js
1 /**
2  * @license AngularJS v1.2.25
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  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
34  */
35
36 function minErr(module) {
37   return function () {
38     var code = arguments[0],
39       prefix = '[' + (module ? module + ':' : '') + code + '] ',
40       template = arguments[1],
41       templateArgs = arguments,
42       stringify = function (obj) {
43         if (typeof obj === 'function') {
44           return obj.toString().replace(/ \{[\s\S]*$/, '');
45         } else if (typeof obj === 'undefined') {
46           return 'undefined';
47         } else if (typeof obj !== 'string') {
48           return JSON.stringify(obj);
49         }
50         return obj;
51       },
52       message, i;
53
54     message = prefix + template.replace(/\{\d+\}/g, function (match) {
55       var index = +match.slice(1, -1), arg;
56
57       if (index + 2 < templateArgs.length) {
58         arg = templateArgs[index + 2];
59         if (typeof arg === 'function') {
60           return arg.toString().replace(/ ?\{[\s\S]*$/, '');
61         } else if (typeof arg === 'undefined') {
62           return 'undefined';
63         } else if (typeof arg !== 'string') {
64           return toJson(arg);
65         }
66         return arg;
67       }
68       return match;
69     });
70
71     message = message + '\nhttp://errors.angularjs.org/1.2.25/' +
72       (module ? module + '/' : '') + code;
73     for (i = 2; i < arguments.length; i++) {
74       message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
75         encodeURIComponent(stringify(arguments[i]));
76     }
77
78     return new Error(message);
79   };
80 }
81
82 /* We need to tell jshint what variables are being exported */
83 /* global angular: true,
84     msie: true,
85     jqLite: true,
86     jQuery: true,
87     slice: true,
88     push: true,
89     toString: true,
90     ngMinErr: true,
91     angularModule: true,
92     nodeName_: true,
93     uid: true,
94     VALIDITY_STATE_PROPERTY: true,
95
96     lowercase: true,
97     uppercase: true,
98     manualLowercase: true,
99     manualUppercase: true,
100     nodeName_: true,
101     isArrayLike: true,
102     forEach: true,
103     sortedKeys: true,
104     forEachSorted: true,
105     reverseParams: true,
106     nextUid: true,
107     setHashKey: true,
108     extend: true,
109     int: true,
110     inherit: true,
111     noop: true,
112     identity: true,
113     valueFn: true,
114     isUndefined: true,
115     isDefined: true,
116     isObject: true,
117     isString: true,
118     isNumber: true,
119     isDate: true,
120     isArray: true,
121     isFunction: true,
122     isRegExp: true,
123     isWindow: true,
124     isScope: true,
125     isFile: true,
126     isBlob: true,
127     isBoolean: true,
128     isPromiseLike: true,
129     trim: true,
130     isElement: true,
131     makeMap: true,
132     map: true,
133     size: true,
134     includes: true,
135     indexOf: true,
136     arrayRemove: true,
137     isLeafNode: true,
138     copy: true,
139     shallowCopy: true,
140     equals: true,
141     csp: true,
142     concat: true,
143     sliceArgs: true,
144     bind: true,
145     toJsonReplacer: true,
146     toJson: true,
147     fromJson: true,
148     toBoolean: true,
149     startingTag: true,
150     tryDecodeURIComponent: true,
151     parseKeyValue: true,
152     toKeyValue: true,
153     encodeUriSegment: true,
154     encodeUriQuery: true,
155     angularInit: true,
156     bootstrap: true,
157     snake_case: true,
158     bindJQuery: true,
159     assertArg: true,
160     assertArgFn: true,
161     assertNotHasOwnProperty: true,
162     getter: true,
163     getBlockElements: true,
164     hasOwnProperty: true,
165 */
166
167 ////////////////////////////////////
168
169 /**
170  * @ngdoc module
171  * @name ng
172  * @module ng
173  * @description
174  *
175  * # ng (core module)
176  * The ng module is loaded by default when an AngularJS application is started. The module itself
177  * contains the essential components for an AngularJS application to function. The table below
178  * lists a high level breakdown of each of the services/factories, filters, directives and testing
179  * components available within this core module.
180  *
181  * <div doc-module-components="ng"></div>
182  */
183
184 // The name of a form control's ValidityState property.
185 // This is used so that it's possible for internal tests to create mock ValidityStates.
186 var VALIDITY_STATE_PROPERTY = 'validity';
187
188 /**
189  * @ngdoc function
190  * @name angular.lowercase
191  * @module ng
192  * @kind function
193  *
194  * @description Converts the specified string to lowercase.
195  * @param {string} string String to be converted to lowercase.
196  * @returns {string} Lowercased string.
197  */
198 var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
199 var hasOwnProperty = Object.prototype.hasOwnProperty;
200
201 /**
202  * @ngdoc function
203  * @name angular.uppercase
204  * @module ng
205  * @kind function
206  *
207  * @description Converts the specified string to uppercase.
208  * @param {string} string String to be converted to uppercase.
209  * @returns {string} Uppercased string.
210  */
211 var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
212
213
214 var manualLowercase = function(s) {
215   /* jshint bitwise: false */
216   return isString(s)
217       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
218       : s;
219 };
220 var manualUppercase = function(s) {
221   /* jshint bitwise: false */
222   return isString(s)
223       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
224       : s;
225 };
226
227
228 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
229 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
230 // with correct but slower alternatives.
231 if ('i' !== 'I'.toLowerCase()) {
232   lowercase = manualLowercase;
233   uppercase = manualUppercase;
234 }
235
236
237 var /** holds major version number for IE or NaN for real browsers */
238     msie,
239     jqLite,           // delay binding since jQuery could be loaded after us.
240     jQuery,           // delay binding
241     slice             = [].slice,
242     push              = [].push,
243     toString          = Object.prototype.toString,
244     ngMinErr          = minErr('ng'),
245
246     /** @name angular */
247     angular           = window.angular || (window.angular = {}),
248     angularModule,
249     nodeName_,
250     uid               = ['0', '0', '0'];
251
252 /**
253  * IE 11 changed the format of the UserAgent string.
254  * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
255  */
256 msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
257 if (isNaN(msie)) {
258   msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
259 }
260
261
262 /**
263  * @private
264  * @param {*} obj
265  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
266  *                   String ...)
267  */
268 function isArrayLike(obj) {
269   if (obj == null || isWindow(obj)) {
270     return false;
271   }
272
273   var length = obj.length;
274
275   if (obj.nodeType === 1 && length) {
276     return true;
277   }
278
279   return isString(obj) || isArray(obj) || length === 0 ||
280          typeof length === 'number' && length > 0 && (length - 1) in obj;
281 }
282
283 /**
284  * @ngdoc function
285  * @name angular.forEach
286  * @module ng
287  * @kind function
288  *
289  * @description
290  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
291  * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
292  * is the value of an object property or an array element and `key` is the object property key or
293  * array element index. Specifying a `context` for the function is optional.
294  *
295  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
296  * using the `hasOwnProperty` method.
297  *
298    ```js
299      var values = {name: 'misko', gender: 'male'};
300      var log = [];
301      angular.forEach(values, function(value, key) {
302        this.push(key + ': ' + value);
303      }, log);
304      expect(log).toEqual(['name: misko', 'gender: male']);
305    ```
306  *
307  * @param {Object|Array} obj Object to iterate over.
308  * @param {Function} iterator Iterator function.
309  * @param {Object=} context Object to become context (`this`) for the iterator function.
310  * @returns {Object|Array} Reference to `obj`.
311  */
312 function forEach(obj, iterator, context) {
313   var key;
314   if (obj) {
315     if (isFunction(obj)) {
316       for (key in obj) {
317         // Need to check if hasOwnProperty exists,
318         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
319         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
320           iterator.call(context, obj[key], key);
321         }
322       }
323     } else if (isArray(obj) || isArrayLike(obj)) {
324       for (key = 0; key < obj.length; key++) {
325         iterator.call(context, obj[key], key);
326       }
327     } else if (obj.forEach && obj.forEach !== forEach) {
328         obj.forEach(iterator, context);
329     } else {
330       for (key in obj) {
331         if (obj.hasOwnProperty(key)) {
332           iterator.call(context, obj[key], key);
333         }
334       }
335     }
336   }
337   return obj;
338 }
339
340 function sortedKeys(obj) {
341   var keys = [];
342   for (var key in obj) {
343     if (obj.hasOwnProperty(key)) {
344       keys.push(key);
345     }
346   }
347   return keys.sort();
348 }
349
350 function forEachSorted(obj, iterator, context) {
351   var keys = sortedKeys(obj);
352   for ( var i = 0; i < keys.length; i++) {
353     iterator.call(context, obj[keys[i]], keys[i]);
354   }
355   return keys;
356 }
357
358
359 /**
360  * when using forEach the params are value, key, but it is often useful to have key, value.
361  * @param {function(string, *)} iteratorFn
362  * @returns {function(*, string)}
363  */
364 function reverseParams(iteratorFn) {
365   return function(value, key) { iteratorFn(key, value); };
366 }
367
368 /**
369  * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
370  * characters such as '012ABC'. The reason why we are not using simply a number counter is that
371  * the number string gets longer over time, and it can also overflow, where as the nextId
372  * will grow much slower, it is a string, and it will never overflow.
373  *
374  * @returns {string} an unique alpha-numeric string
375  */
376 function nextUid() {
377   var index = uid.length;
378   var digit;
379
380   while(index) {
381     index--;
382     digit = uid[index].charCodeAt(0);
383     if (digit == 57 /*'9'*/) {
384       uid[index] = 'A';
385       return uid.join('');
386     }
387     if (digit == 90  /*'Z'*/) {
388       uid[index] = '0';
389     } else {
390       uid[index] = String.fromCharCode(digit + 1);
391       return uid.join('');
392     }
393   }
394   uid.unshift('0');
395   return uid.join('');
396 }
397
398
399 /**
400  * Set or clear the hashkey for an object.
401  * @param obj object
402  * @param h the hashkey (!truthy to delete the hashkey)
403  */
404 function setHashKey(obj, h) {
405   if (h) {
406     obj.$$hashKey = h;
407   }
408   else {
409     delete obj.$$hashKey;
410   }
411 }
412
413 /**
414  * @ngdoc function
415  * @name angular.extend
416  * @module ng
417  * @kind function
418  *
419  * @description
420  * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
421  * to `dst`. You can specify multiple `src` objects.
422  *
423  * @param {Object} dst Destination object.
424  * @param {...Object} src Source object(s).
425  * @returns {Object} Reference to `dst`.
426  */
427 function extend(dst) {
428   var h = dst.$$hashKey;
429   forEach(arguments, function(obj) {
430     if (obj !== dst) {
431       forEach(obj, function(value, key) {
432         dst[key] = value;
433       });
434     }
435   });
436
437   setHashKey(dst,h);
438   return dst;
439 }
440
441 function int(str) {
442   return parseInt(str, 10);
443 }
444
445
446 function inherit(parent, extra) {
447   return extend(new (extend(function() {}, {prototype:parent}))(), extra);
448 }
449
450 /**
451  * @ngdoc function
452  * @name angular.noop
453  * @module ng
454  * @kind function
455  *
456  * @description
457  * A function that performs no operations. This function can be useful when writing code in the
458  * functional style.
459    ```js
460      function foo(callback) {
461        var result = calculateResult();
462        (callback || angular.noop)(result);
463      }
464    ```
465  */
466 function noop() {}
467 noop.$inject = [];
468
469
470 /**
471  * @ngdoc function
472  * @name angular.identity
473  * @module ng
474  * @kind function
475  *
476  * @description
477  * A function that returns its first argument. This function is useful when writing code in the
478  * functional style.
479  *
480    ```js
481      function transformer(transformationFn, value) {
482        return (transformationFn || angular.identity)(value);
483      };
484    ```
485  */
486 function identity($) {return $;}
487 identity.$inject = [];
488
489
490 function valueFn(value) {return function() {return value;};}
491
492 /**
493  * @ngdoc function
494  * @name angular.isUndefined
495  * @module ng
496  * @kind function
497  *
498  * @description
499  * Determines if a reference is undefined.
500  *
501  * @param {*} value Reference to check.
502  * @returns {boolean} True if `value` is undefined.
503  */
504 function isUndefined(value){return typeof value === 'undefined';}
505
506
507 /**
508  * @ngdoc function
509  * @name angular.isDefined
510  * @module ng
511  * @kind function
512  *
513  * @description
514  * Determines if a reference is defined.
515  *
516  * @param {*} value Reference to check.
517  * @returns {boolean} True if `value` is defined.
518  */
519 function isDefined(value){return typeof value !== 'undefined';}
520
521
522 /**
523  * @ngdoc function
524  * @name angular.isObject
525  * @module ng
526  * @kind function
527  *
528  * @description
529  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
530  * considered to be objects. Note that JavaScript arrays are objects.
531  *
532  * @param {*} value Reference to check.
533  * @returns {boolean} True if `value` is an `Object` but not `null`.
534  */
535 function isObject(value){return value != null && typeof value === 'object';}
536
537
538 /**
539  * @ngdoc function
540  * @name angular.isString
541  * @module ng
542  * @kind function
543  *
544  * @description
545  * Determines if a reference is a `String`.
546  *
547  * @param {*} value Reference to check.
548  * @returns {boolean} True if `value` is a `String`.
549  */
550 function isString(value){return typeof value === 'string';}
551
552
553 /**
554  * @ngdoc function
555  * @name angular.isNumber
556  * @module ng
557  * @kind function
558  *
559  * @description
560  * Determines if a reference is a `Number`.
561  *
562  * @param {*} value Reference to check.
563  * @returns {boolean} True if `value` is a `Number`.
564  */
565 function isNumber(value){return typeof value === 'number';}
566
567
568 /**
569  * @ngdoc function
570  * @name angular.isDate
571  * @module ng
572  * @kind function
573  *
574  * @description
575  * Determines if a value is a date.
576  *
577  * @param {*} value Reference to check.
578  * @returns {boolean} True if `value` is a `Date`.
579  */
580 function isDate(value) {
581   return toString.call(value) === '[object Date]';
582 }
583
584
585 /**
586  * @ngdoc function
587  * @name angular.isArray
588  * @module ng
589  * @kind function
590  *
591  * @description
592  * Determines if a reference is an `Array`.
593  *
594  * @param {*} value Reference to check.
595  * @returns {boolean} True if `value` is an `Array`.
596  */
597 var isArray = (function() {
598   if (!isFunction(Array.isArray)) {
599     return function(value) {
600       return toString.call(value) === '[object Array]';
601     };
602   }
603   return Array.isArray;
604 })();
605
606 /**
607  * @ngdoc function
608  * @name angular.isFunction
609  * @module ng
610  * @kind function
611  *
612  * @description
613  * Determines if a reference is a `Function`.
614  *
615  * @param {*} value Reference to check.
616  * @returns {boolean} True if `value` is a `Function`.
617  */
618 function isFunction(value){return typeof value === 'function';}
619
620
621 /**
622  * Determines if a value is a regular expression object.
623  *
624  * @private
625  * @param {*} value Reference to check.
626  * @returns {boolean} True if `value` is a `RegExp`.
627  */
628 function isRegExp(value) {
629   return toString.call(value) === '[object RegExp]';
630 }
631
632
633 /**
634  * Checks if `obj` is a window object.
635  *
636  * @private
637  * @param {*} obj Object to check
638  * @returns {boolean} True if `obj` is a window obj.
639  */
640 function isWindow(obj) {
641   return obj && obj.document && obj.location && obj.alert && obj.setInterval;
642 }
643
644
645 function isScope(obj) {
646   return obj && obj.$evalAsync && obj.$watch;
647 }
648
649
650 function isFile(obj) {
651   return toString.call(obj) === '[object File]';
652 }
653
654
655 function isBlob(obj) {
656   return toString.call(obj) === '[object Blob]';
657 }
658
659
660 function isBoolean(value) {
661   return typeof value === 'boolean';
662 }
663
664
665 function isPromiseLike(obj) {
666   return obj && isFunction(obj.then);
667 }
668
669
670 var trim = (function() {
671   // native trim is way faster: http://jsperf.com/angular-trim-test
672   // but IE doesn't have it... :-(
673   // TODO: we should move this into IE/ES5 polyfill
674   if (!String.prototype.trim) {
675     return function(value) {
676       return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
677     };
678   }
679   return function(value) {
680     return isString(value) ? value.trim() : value;
681   };
682 })();
683
684
685 /**
686  * @ngdoc function
687  * @name angular.isElement
688  * @module ng
689  * @kind function
690  *
691  * @description
692  * Determines if a reference is a DOM element (or wrapped jQuery element).
693  *
694  * @param {*} value Reference to check.
695  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
696  */
697 function isElement(node) {
698   return !!(node &&
699     (node.nodeName  // we are a direct element
700     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
701 }
702
703 /**
704  * @param str 'key1,key2,...'
705  * @returns {object} in the form of {key1:true, key2:true, ...}
706  */
707 function makeMap(str) {
708   var obj = {}, items = str.split(","), i;
709   for ( i = 0; i < items.length; i++ )
710     obj[ items[i] ] = true;
711   return obj;
712 }
713
714
715 if (msie < 9) {
716   nodeName_ = function(element) {
717     element = element.nodeName ? element : element[0];
718     return (element.scopeName && element.scopeName != 'HTML')
719       ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
720   };
721 } else {
722   nodeName_ = function(element) {
723     return element.nodeName ? element.nodeName : element[0].nodeName;
724   };
725 }
726
727
728 function map(obj, iterator, context) {
729   var results = [];
730   forEach(obj, function(value, index, list) {
731     results.push(iterator.call(context, value, index, list));
732   });
733   return results;
734 }
735
736
737 /**
738  * @description
739  * Determines the number of elements in an array, the number of properties an object has, or
740  * the length of a string.
741  *
742  * Note: This function is used to augment the Object type in Angular expressions. See
743  * {@link angular.Object} for more information about Angular arrays.
744  *
745  * @param {Object|Array|string} obj Object, array, or string to inspect.
746  * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
747  * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
748  */
749 function size(obj, ownPropsOnly) {
750   var count = 0, key;
751
752   if (isArray(obj) || isString(obj)) {
753     return obj.length;
754   } else if (isObject(obj)) {
755     for (key in obj)
756       if (!ownPropsOnly || obj.hasOwnProperty(key))
757         count++;
758   }
759
760   return count;
761 }
762
763
764 function includes(array, obj) {
765   return indexOf(array, obj) != -1;
766 }
767
768 function indexOf(array, obj) {
769   if (array.indexOf) return array.indexOf(obj);
770
771   for (var i = 0; i < array.length; i++) {
772     if (obj === array[i]) return i;
773   }
774   return -1;
775 }
776
777 function arrayRemove(array, value) {
778   var index = indexOf(array, value);
779   if (index >=0)
780     array.splice(index, 1);
781   return value;
782 }
783
784 function isLeafNode (node) {
785   if (node) {
786     switch (node.nodeName) {
787     case "OPTION":
788     case "PRE":
789     case "TITLE":
790       return true;
791     }
792   }
793   return false;
794 }
795
796 /**
797  * @ngdoc function
798  * @name angular.copy
799  * @module ng
800  * @kind function
801  *
802  * @description
803  * Creates a deep copy of `source`, which should be an object or an array.
804  *
805  * * If no destination is supplied, a copy of the object or array is created.
806  * * If a destination is provided, all of its elements (for array) or properties (for objects)
807  *   are deleted and then all elements/properties from the source are copied to it.
808  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
809  * * If `source` is identical to 'destination' an exception will be thrown.
810  *
811  * @param {*} source The source that will be used to make a copy.
812  *                   Can be any type, including primitives, `null`, and `undefined`.
813  * @param {(Object|Array)=} destination Destination into which the source is copied. If
814  *     provided, must be of the same type as `source`.
815  * @returns {*} The copy or updated `destination`, if `destination` was specified.
816  *
817  * @example
818  <example module="copyExample">
819  <file name="index.html">
820  <div ng-controller="ExampleController">
821  <form novalidate class="simple-form">
822  Name: <input type="text" ng-model="user.name" /><br />
823  E-mail: <input type="email" ng-model="user.email" /><br />
824  Gender: <input type="radio" ng-model="user.gender" value="male" />male
825  <input type="radio" ng-model="user.gender" value="female" />female<br />
826  <button ng-click="reset()">RESET</button>
827  <button ng-click="update(user)">SAVE</button>
828  </form>
829  <pre>form = {{user | json}}</pre>
830  <pre>master = {{master | json}}</pre>
831  </div>
832
833  <script>
834   angular.module('copyExample', [])
835     .controller('ExampleController', ['$scope', function($scope) {
836       $scope.master= {};
837
838       $scope.update = function(user) {
839         // Example with 1 argument
840         $scope.master= angular.copy(user);
841       };
842
843       $scope.reset = function() {
844         // Example with 2 arguments
845         angular.copy($scope.master, $scope.user);
846       };
847
848       $scope.reset();
849     }]);
850  </script>
851  </file>
852  </example>
853  */
854 function copy(source, destination, stackSource, stackDest) {
855   if (isWindow(source) || isScope(source)) {
856     throw ngMinErr('cpws',
857       "Can't copy! Making copies of Window or Scope instances is not supported.");
858   }
859
860   if (!destination) {
861     destination = source;
862     if (source) {
863       if (isArray(source)) {
864         destination = copy(source, [], stackSource, stackDest);
865       } else if (isDate(source)) {
866         destination = new Date(source.getTime());
867       } else if (isRegExp(source)) {
868         destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
869         destination.lastIndex = source.lastIndex;
870       } else if (isObject(source)) {
871         destination = copy(source, {}, stackSource, stackDest);
872       }
873     }
874   } else {
875     if (source === destination) throw ngMinErr('cpi',
876       "Can't copy! Source and destination are identical.");
877
878     stackSource = stackSource || [];
879     stackDest = stackDest || [];
880
881     if (isObject(source)) {
882       var index = indexOf(stackSource, source);
883       if (index !== -1) return stackDest[index];
884
885       stackSource.push(source);
886       stackDest.push(destination);
887     }
888
889     var result;
890     if (isArray(source)) {
891       destination.length = 0;
892       for ( var i = 0; i < source.length; i++) {
893         result = copy(source[i], null, stackSource, stackDest);
894         if (isObject(source[i])) {
895           stackSource.push(source[i]);
896           stackDest.push(result);
897         }
898         destination.push(result);
899       }
900     } else {
901       var h = destination.$$hashKey;
902       if (isArray(destination)) {
903         destination.length = 0;
904       } else {
905         forEach(destination, function(value, key) {
906           delete destination[key];
907         });
908       }
909       for ( var key in source) {
910         result = copy(source[key], null, stackSource, stackDest);
911         if (isObject(source[key])) {
912           stackSource.push(source[key]);
913           stackDest.push(result);
914         }
915         destination[key] = result;
916       }
917       setHashKey(destination,h);
918     }
919
920   }
921   return destination;
922 }
923
924 /**
925  * Creates a shallow copy of an object, an array or a primitive
926  */
927 function shallowCopy(src, dst) {
928   if (isArray(src)) {
929     dst = dst || [];
930
931     for ( var i = 0; i < src.length; i++) {
932       dst[i] = src[i];
933     }
934   } else if (isObject(src)) {
935     dst = dst || {};
936
937     for (var key in src) {
938       if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
939         dst[key] = src[key];
940       }
941     }
942   }
943
944   return dst || src;
945 }
946
947
948 /**
949  * @ngdoc function
950  * @name angular.equals
951  * @module ng
952  * @kind function
953  *
954  * @description
955  * Determines if two objects or two values are equivalent. Supports value types, regular
956  * expressions, arrays and objects.
957  *
958  * Two objects or values are considered equivalent if at least one of the following is true:
959  *
960  * * Both objects or values pass `===` comparison.
961  * * Both objects or values are of the same type and all of their properties are equal by
962  *   comparing them with `angular.equals`.
963  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
964  * * Both values represent the same regular expression (In JavaScript,
965  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
966  *   representation matches).
967  *
968  * During a property comparison, properties of `function` type and properties with names
969  * that begin with `$` are ignored.
970  *
971  * Scope and DOMWindow objects are being compared only by identify (`===`).
972  *
973  * @param {*} o1 Object or value to compare.
974  * @param {*} o2 Object or value to compare.
975  * @returns {boolean} True if arguments are equal.
976  */
977 function equals(o1, o2) {
978   if (o1 === o2) return true;
979   if (o1 === null || o2 === null) return false;
980   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
981   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
982   if (t1 == t2) {
983     if (t1 == 'object') {
984       if (isArray(o1)) {
985         if (!isArray(o2)) return false;
986         if ((length = o1.length) == o2.length) {
987           for(key=0; key<length; key++) {
988             if (!equals(o1[key], o2[key])) return false;
989           }
990           return true;
991         }
992       } else if (isDate(o1)) {
993         if (!isDate(o2)) return false;
994         return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
995       } else if (isRegExp(o1) && isRegExp(o2)) {
996         return o1.toString() == o2.toString();
997       } else {
998         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
999         keySet = {};
1000         for(key in o1) {
1001           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1002           if (!equals(o1[key], o2[key])) return false;
1003           keySet[key] = true;
1004         }
1005         for(key in o2) {
1006           if (!keySet.hasOwnProperty(key) &&
1007               key.charAt(0) !== '$' &&
1008               o2[key] !== undefined &&
1009               !isFunction(o2[key])) return false;
1010         }
1011         return true;
1012       }
1013     }
1014   }
1015   return false;
1016 }
1017
1018 var csp = function() {
1019   if (isDefined(csp.isActive_)) return csp.isActive_;
1020
1021   var active = !!(document.querySelector('[ng-csp]') ||
1022                   document.querySelector('[data-ng-csp]'));
1023
1024   if (!active) {
1025     try {
1026       /* jshint -W031, -W054 */
1027       new Function('');
1028       /* jshint +W031, +W054 */
1029     } catch (e) {
1030       active = true;
1031     }
1032   }
1033
1034   return (csp.isActive_ = active);
1035 };
1036
1037
1038
1039 function concat(array1, array2, index) {
1040   return array1.concat(slice.call(array2, index));
1041 }
1042
1043 function sliceArgs(args, startIndex) {
1044   return slice.call(args, startIndex || 0);
1045 }
1046
1047
1048 /* jshint -W101 */
1049 /**
1050  * @ngdoc function
1051  * @name angular.bind
1052  * @module ng
1053  * @kind function
1054  *
1055  * @description
1056  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1057  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1058  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1059  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1060  *
1061  * @param {Object} self Context which `fn` should be evaluated in.
1062  * @param {function()} fn Function to be bound.
1063  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1064  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1065  */
1066 /* jshint +W101 */
1067 function bind(self, fn) {
1068   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1069   if (isFunction(fn) && !(fn instanceof RegExp)) {
1070     return curryArgs.length
1071       ? function() {
1072           return arguments.length
1073             ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1074             : fn.apply(self, curryArgs);
1075         }
1076       : function() {
1077           return arguments.length
1078             ? fn.apply(self, arguments)
1079             : fn.call(self);
1080         };
1081   } else {
1082     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1083     return fn;
1084   }
1085 }
1086
1087
1088 function toJsonReplacer(key, value) {
1089   var val = value;
1090
1091   if (typeof key === 'string' && key.charAt(0) === '$') {
1092     val = undefined;
1093   } else if (isWindow(value)) {
1094     val = '$WINDOW';
1095   } else if (value &&  document === value) {
1096     val = '$DOCUMENT';
1097   } else if (isScope(value)) {
1098     val = '$SCOPE';
1099   }
1100
1101   return val;
1102 }
1103
1104
1105 /**
1106  * @ngdoc function
1107  * @name angular.toJson
1108  * @module ng
1109  * @kind function
1110  *
1111  * @description
1112  * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1113  * stripped since angular uses this notation internally.
1114  *
1115  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1116  * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
1117  * @returns {string|undefined} JSON-ified string representing `obj`.
1118  */
1119 function toJson(obj, pretty) {
1120   if (typeof obj === 'undefined') return undefined;
1121   return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1122 }
1123
1124
1125 /**
1126  * @ngdoc function
1127  * @name angular.fromJson
1128  * @module ng
1129  * @kind function
1130  *
1131  * @description
1132  * Deserializes a JSON string.
1133  *
1134  * @param {string} json JSON string to deserialize.
1135  * @returns {Object|Array|string|number} Deserialized thingy.
1136  */
1137 function fromJson(json) {
1138   return isString(json)
1139       ? JSON.parse(json)
1140       : json;
1141 }
1142
1143
1144 function toBoolean(value) {
1145   if (typeof value === 'function') {
1146     value = true;
1147   } else if (value && value.length !== 0) {
1148     var v = lowercase("" + value);
1149     value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1150   } else {
1151     value = false;
1152   }
1153   return value;
1154 }
1155
1156 /**
1157  * @returns {string} Returns the string representation of the element.
1158  */
1159 function startingTag(element) {
1160   element = jqLite(element).clone();
1161   try {
1162     // turns out IE does not let you set .html() on elements which
1163     // are not allowed to have children. So we just ignore it.
1164     element.empty();
1165   } catch(e) {}
1166   // As Per DOM Standards
1167   var TEXT_NODE = 3;
1168   var elemHtml = jqLite('<div>').append(element).html();
1169   try {
1170     return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1171         elemHtml.
1172           match(/^(<[^>]+>)/)[1].
1173           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1174   } catch(e) {
1175     return lowercase(elemHtml);
1176   }
1177
1178 }
1179
1180
1181 /////////////////////////////////////////////////
1182
1183 /**
1184  * Tries to decode the URI component without throwing an exception.
1185  *
1186  * @private
1187  * @param str value potential URI component to check.
1188  * @returns {boolean} True if `value` can be decoded
1189  * with the decodeURIComponent function.
1190  */
1191 function tryDecodeURIComponent(value) {
1192   try {
1193     return decodeURIComponent(value);
1194   } catch(e) {
1195     // Ignore any invalid uri component
1196   }
1197 }
1198
1199
1200 /**
1201  * Parses an escaped url query string into key-value pairs.
1202  * @returns {Object.<string,boolean|Array>}
1203  */
1204 function parseKeyValue(/**string*/keyValue) {
1205   var obj = {}, key_value, key;
1206   forEach((keyValue || "").split('&'), function(keyValue) {
1207     if ( keyValue ) {
1208       key_value = keyValue.replace(/\+/g,'%20').split('=');
1209       key = tryDecodeURIComponent(key_value[0]);
1210       if ( isDefined(key) ) {
1211         var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1212         if (!hasOwnProperty.call(obj, key)) {
1213           obj[key] = val;
1214         } else if(isArray(obj[key])) {
1215           obj[key].push(val);
1216         } else {
1217           obj[key] = [obj[key],val];
1218         }
1219       }
1220     }
1221   });
1222   return obj;
1223 }
1224
1225 function toKeyValue(obj) {
1226   var parts = [];
1227   forEach(obj, function(value, key) {
1228     if (isArray(value)) {
1229       forEach(value, function(arrayValue) {
1230         parts.push(encodeUriQuery(key, true) +
1231                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1232       });
1233     } else {
1234     parts.push(encodeUriQuery(key, true) +
1235                (value === true ? '' : '=' + encodeUriQuery(value, true)));
1236     }
1237   });
1238   return parts.length ? parts.join('&') : '';
1239 }
1240
1241
1242 /**
1243  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1244  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1245  * segments:
1246  *    segment       = *pchar
1247  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1248  *    pct-encoded   = "%" HEXDIG HEXDIG
1249  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1250  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1251  *                     / "*" / "+" / "," / ";" / "="
1252  */
1253 function encodeUriSegment(val) {
1254   return encodeUriQuery(val, true).
1255              replace(/%26/gi, '&').
1256              replace(/%3D/gi, '=').
1257              replace(/%2B/gi, '+');
1258 }
1259
1260
1261 /**
1262  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1263  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1264  * encoded per http://tools.ietf.org/html/rfc3986:
1265  *    query       = *( pchar / "/" / "?" )
1266  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1267  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1268  *    pct-encoded   = "%" HEXDIG HEXDIG
1269  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1270  *                     / "*" / "+" / "," / ";" / "="
1271  */
1272 function encodeUriQuery(val, pctEncodeSpaces) {
1273   return encodeURIComponent(val).
1274              replace(/%40/gi, '@').
1275              replace(/%3A/gi, ':').
1276              replace(/%24/g, '$').
1277              replace(/%2C/gi, ',').
1278              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1279 }
1280
1281
1282 /**
1283  * @ngdoc directive
1284  * @name ngApp
1285  * @module ng
1286  *
1287  * @element ANY
1288  * @param {angular.Module} ngApp an optional application
1289  *   {@link angular.module module} name to load.
1290  *
1291  * @description
1292  *
1293  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1294  * designates the **root element** of the application and is typically placed near the root element
1295  * of the page - e.g. on the `<body>` or `<html>` tags.
1296  *
1297  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1298  * found in the document will be used to define the root element to auto-bootstrap as an
1299  * application. To run multiple applications in an HTML document you must manually bootstrap them using
1300  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1301  *
1302  * You can specify an **AngularJS module** to be used as the root module for the application.  This
1303  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1304  * should contain the application code needed or have dependencies on other modules that will
1305  * contain the code. See {@link angular.module} for more information.
1306  *
1307  * In the example below if the `ngApp` directive were not placed on the `html` element then the
1308  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1309  * would not be resolved to `3`.
1310  *
1311  * `ngApp` is the easiest, and most common, way to bootstrap an application.
1312  *
1313  <example module="ngAppDemo">
1314    <file name="index.html">
1315    <div ng-controller="ngAppDemoController">
1316      I can add: {{a}} + {{b}} =  {{ a+b }}
1317    </div>
1318    </file>
1319    <file name="script.js">
1320    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1321      $scope.a = 1;
1322      $scope.b = 2;
1323    });
1324    </file>
1325  </example>
1326  *
1327  */
1328 function angularInit(element, bootstrap) {
1329   var elements = [element],
1330       appElement,
1331       module,
1332       names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1333       NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1334
1335   function append(element) {
1336     element && elements.push(element);
1337   }
1338
1339   forEach(names, function(name) {
1340     names[name] = true;
1341     append(document.getElementById(name));
1342     name = name.replace(':', '\\:');
1343     if (element.querySelectorAll) {
1344       forEach(element.querySelectorAll('.' + name), append);
1345       forEach(element.querySelectorAll('.' + name + '\\:'), append);
1346       forEach(element.querySelectorAll('[' + name + ']'), append);
1347     }
1348   });
1349
1350   forEach(elements, function(element) {
1351     if (!appElement) {
1352       var className = ' ' + element.className + ' ';
1353       var match = NG_APP_CLASS_REGEXP.exec(className);
1354       if (match) {
1355         appElement = element;
1356         module = (match[2] || '').replace(/\s+/g, ',');
1357       } else {
1358         forEach(element.attributes, function(attr) {
1359           if (!appElement && names[attr.name]) {
1360             appElement = element;
1361             module = attr.value;
1362           }
1363         });
1364       }
1365     }
1366   });
1367   if (appElement) {
1368     bootstrap(appElement, module ? [module] : []);
1369   }
1370 }
1371
1372 /**
1373  * @ngdoc function
1374  * @name angular.bootstrap
1375  * @module ng
1376  * @description
1377  * Use this function to manually start up angular application.
1378  *
1379  * See: {@link guide/bootstrap Bootstrap}
1380  *
1381  * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1382  * They must use {@link ng.directive:ngApp ngApp}.
1383  *
1384  * Angular will detect if it has been loaded into the browser more than once and only allow the
1385  * first loaded script to be bootstrapped and will report a warning to the browser console for
1386  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1387  * multiple instances of Angular try to work on the DOM.
1388  *
1389  * <example name="multi-bootstrap" module="multi-bootstrap">
1390  * <file name="index.html">
1391  * <script src="../../../angular.js"></script>
1392  * <div ng-controller="BrokenTable">
1393  *   <table>
1394  *   <tr>
1395  *     <th ng-repeat="heading in headings">{{heading}}</th>
1396  *   </tr>
1397  *   <tr ng-repeat="filling in fillings">
1398  *     <td ng-repeat="fill in filling">{{fill}}</td>
1399  *   </tr>
1400  * </table>
1401  * </div>
1402  * </file>
1403  * <file name="controller.js">
1404  * var app = angular.module('multi-bootstrap', [])
1405  *
1406  * .controller('BrokenTable', function($scope) {
1407  *     $scope.headings = ['One', 'Two', 'Three'];
1408  *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1409  * });
1410  * </file>
1411  * <file name="protractor.js" type="protractor">
1412  * it('should only insert one table cell for each item in $scope.fillings', function() {
1413  *  expect(element.all(by.css('td')).count())
1414  *      .toBe(9);
1415  * });
1416  * </file>
1417  * </example>
1418  *
1419  * @param {DOMElement} element DOM element which is the root of angular application.
1420  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1421  *     Each item in the array should be the name of a predefined module or a (DI annotated)
1422  *     function that will be invoked by the injector as a run block.
1423  *     See: {@link angular.module modules}
1424  * @returns {auto.$injector} Returns the newly created injector for this app.
1425  */
1426 function bootstrap(element, modules) {
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     modules.unshift('ng');
1444     var injector = createInjector(modules);
1445     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1446        function(scope, element, compile, injector, animate) {
1447         scope.$apply(function() {
1448           element.data('$injector', injector);
1449           compile(element)(scope);
1450         });
1451       }]
1452     );
1453     return injector;
1454   };
1455
1456   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1457
1458   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1459     return doBootstrap();
1460   }
1461
1462   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1463   angular.resumeBootstrap = function(extraModules) {
1464     forEach(extraModules, function(module) {
1465       modules.push(module);
1466     });
1467     doBootstrap();
1468   };
1469 }
1470
1471 var SNAKE_CASE_REGEXP = /[A-Z]/g;
1472 function snake_case(name, separator) {
1473   separator = separator || '_';
1474   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1475     return (pos ? separator : '') + letter.toLowerCase();
1476   });
1477 }
1478
1479 function bindJQuery() {
1480   // bind to jQuery if present;
1481   jQuery = window.jQuery;
1482   // Use jQuery if it exists with proper functionality, otherwise default to us.
1483   // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
1484   if (jQuery && jQuery.fn.on) {
1485     jqLite = jQuery;
1486     extend(jQuery.fn, {
1487       scope: JQLitePrototype.scope,
1488       isolateScope: JQLitePrototype.isolateScope,
1489       controller: JQLitePrototype.controller,
1490       injector: JQLitePrototype.injector,
1491       inheritedData: JQLitePrototype.inheritedData
1492     });
1493     // Method signature:
1494     //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1495     jqLitePatchJQueryRemove('remove', true, true, false);
1496     jqLitePatchJQueryRemove('empty', false, false, false);
1497     jqLitePatchJQueryRemove('html', false, false, true);
1498   } else {
1499     jqLite = JQLite;
1500   }
1501   angular.element = jqLite;
1502 }
1503
1504 /**
1505  * throw error if the argument is falsy.
1506  */
1507 function assertArg(arg, name, reason) {
1508   if (!arg) {
1509     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1510   }
1511   return arg;
1512 }
1513
1514 function assertArgFn(arg, name, acceptArrayAnnotation) {
1515   if (acceptArrayAnnotation && isArray(arg)) {
1516       arg = arg[arg.length - 1];
1517   }
1518
1519   assertArg(isFunction(arg), name, 'not a function, got ' +
1520       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1521   return arg;
1522 }
1523
1524 /**
1525  * throw error if the name given is hasOwnProperty
1526  * @param  {String} name    the name to test
1527  * @param  {String} context the context in which the name is used, such as module or directive
1528  */
1529 function assertNotHasOwnProperty(name, context) {
1530   if (name === 'hasOwnProperty') {
1531     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1532   }
1533 }
1534
1535 /**
1536  * Return the value accessible from the object by path. Any undefined traversals are ignored
1537  * @param {Object} obj starting object
1538  * @param {String} path path to traverse
1539  * @param {boolean} [bindFnToScope=true]
1540  * @returns {Object} value as accessible by path
1541  */
1542 //TODO(misko): this function needs to be removed
1543 function getter(obj, path, bindFnToScope) {
1544   if (!path) return obj;
1545   var keys = path.split('.');
1546   var key;
1547   var lastInstance = obj;
1548   var len = keys.length;
1549
1550   for (var i = 0; i < len; i++) {
1551     key = keys[i];
1552     if (obj) {
1553       obj = (lastInstance = obj)[key];
1554     }
1555   }
1556   if (!bindFnToScope && isFunction(obj)) {
1557     return bind(lastInstance, obj);
1558   }
1559   return obj;
1560 }
1561
1562 /**
1563  * Return the DOM siblings between the first and last node in the given array.
1564  * @param {Array} array like object
1565  * @returns {DOMElement} object containing the elements
1566  */
1567 function getBlockElements(nodes) {
1568   var startNode = nodes[0],
1569       endNode = nodes[nodes.length - 1];
1570   if (startNode === endNode) {
1571     return jqLite(startNode);
1572   }
1573
1574   var element = startNode;
1575   var elements = [element];
1576
1577   do {
1578     element = element.nextSibling;
1579     if (!element) break;
1580     elements.push(element);
1581   } while (element !== endNode);
1582
1583   return jqLite(elements);
1584 }
1585
1586 /**
1587  * @ngdoc type
1588  * @name angular.Module
1589  * @module ng
1590  * @description
1591  *
1592  * Interface for configuring angular {@link angular.module modules}.
1593  */
1594
1595 function setupModuleLoader(window) {
1596
1597   var $injectorMinErr = minErr('$injector');
1598   var ngMinErr = minErr('ng');
1599
1600   function ensure(obj, name, factory) {
1601     return obj[name] || (obj[name] = factory());
1602   }
1603
1604   var angular = ensure(window, 'angular', Object);
1605
1606   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1607   angular.$$minErr = angular.$$minErr || minErr;
1608
1609   return ensure(angular, 'module', function() {
1610     /** @type {Object.<string, angular.Module>} */
1611     var modules = {};
1612
1613     /**
1614      * @ngdoc function
1615      * @name angular.module
1616      * @module ng
1617      * @description
1618      *
1619      * The `angular.module` is a global place for creating, registering and retrieving Angular
1620      * modules.
1621      * All modules (angular core or 3rd party) that should be available to an application must be
1622      * registered using this mechanism.
1623      *
1624      * When passed two or more arguments, a new module is created.  If passed only one argument, an
1625      * existing module (the name passed as the first argument to `module`) is retrieved.
1626      *
1627      *
1628      * # Module
1629      *
1630      * A module is a collection of services, directives, controllers, filters, and configuration information.
1631      * `angular.module` is used to configure the {@link auto.$injector $injector}.
1632      *
1633      * ```js
1634      * // Create a new module
1635      * var myModule = angular.module('myModule', []);
1636      *
1637      * // register a new service
1638      * myModule.value('appName', 'MyCoolApp');
1639      *
1640      * // configure existing services inside initialization blocks.
1641      * myModule.config(['$locationProvider', function($locationProvider) {
1642      *   // Configure existing providers
1643      *   $locationProvider.hashPrefix('!');
1644      * }]);
1645      * ```
1646      *
1647      * Then you can create an injector and load your modules like this:
1648      *
1649      * ```js
1650      * var injector = angular.injector(['ng', 'myModule'])
1651      * ```
1652      *
1653      * However it's more likely that you'll just use
1654      * {@link ng.directive:ngApp ngApp} or
1655      * {@link angular.bootstrap} to simplify this process for you.
1656      *
1657      * @param {!string} name The name of the module to create or retrieve.
1658      * @param {!Array.<string>=} requires If specified then new module is being created. If
1659      *        unspecified then the module is being retrieved for further configuration.
1660      * @param {Function=} configFn Optional configuration function for the module. Same as
1661      *        {@link angular.Module#config Module#config()}.
1662      * @returns {module} new module with the {@link angular.Module} api.
1663      */
1664     return function module(name, requires, configFn) {
1665       var assertNotHasOwnProperty = function(name, context) {
1666         if (name === 'hasOwnProperty') {
1667           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1668         }
1669       };
1670
1671       assertNotHasOwnProperty(name, 'module');
1672       if (requires && modules.hasOwnProperty(name)) {
1673         modules[name] = null;
1674       }
1675       return ensure(modules, name, function() {
1676         if (!requires) {
1677           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1678              "the module name or forgot to load it. If registering a module ensure that you " +
1679              "specify the dependencies as the second argument.", name);
1680         }
1681
1682         /** @type {!Array.<Array.<*>>} */
1683         var invokeQueue = [];
1684
1685         /** @type {!Array.<Function>} */
1686         var runBlocks = [];
1687
1688         var config = invokeLater('$injector', 'invoke');
1689
1690         /** @type {angular.Module} */
1691         var moduleInstance = {
1692           // Private state
1693           _invokeQueue: invokeQueue,
1694           _runBlocks: runBlocks,
1695
1696           /**
1697            * @ngdoc property
1698            * @name angular.Module#requires
1699            * @module ng
1700            *
1701            * @description
1702            * Holds the list of modules which the injector will load before the current module is
1703            * loaded.
1704            */
1705           requires: requires,
1706
1707           /**
1708            * @ngdoc property
1709            * @name angular.Module#name
1710            * @module ng
1711            *
1712            * @description
1713            * Name of the module.
1714            */
1715           name: name,
1716
1717
1718           /**
1719            * @ngdoc method
1720            * @name angular.Module#provider
1721            * @module ng
1722            * @param {string} name service name
1723            * @param {Function} providerType Construction function for creating new instance of the
1724            *                                service.
1725            * @description
1726            * See {@link auto.$provide#provider $provide.provider()}.
1727            */
1728           provider: invokeLater('$provide', 'provider'),
1729
1730           /**
1731            * @ngdoc method
1732            * @name angular.Module#factory
1733            * @module ng
1734            * @param {string} name service name
1735            * @param {Function} providerFunction Function for creating new instance of the service.
1736            * @description
1737            * See {@link auto.$provide#factory $provide.factory()}.
1738            */
1739           factory: invokeLater('$provide', 'factory'),
1740
1741           /**
1742            * @ngdoc method
1743            * @name angular.Module#service
1744            * @module ng
1745            * @param {string} name service name
1746            * @param {Function} constructor A constructor function that will be instantiated.
1747            * @description
1748            * See {@link auto.$provide#service $provide.service()}.
1749            */
1750           service: invokeLater('$provide', 'service'),
1751
1752           /**
1753            * @ngdoc method
1754            * @name angular.Module#value
1755            * @module ng
1756            * @param {string} name service name
1757            * @param {*} object Service instance object.
1758            * @description
1759            * See {@link auto.$provide#value $provide.value()}.
1760            */
1761           value: invokeLater('$provide', 'value'),
1762
1763           /**
1764            * @ngdoc method
1765            * @name angular.Module#constant
1766            * @module ng
1767            * @param {string} name constant name
1768            * @param {*} object Constant value.
1769            * @description
1770            * Because the constant are fixed, they get applied before other provide methods.
1771            * See {@link auto.$provide#constant $provide.constant()}.
1772            */
1773           constant: invokeLater('$provide', 'constant', 'unshift'),
1774
1775           /**
1776            * @ngdoc method
1777            * @name angular.Module#animation
1778            * @module ng
1779            * @param {string} name animation name
1780            * @param {Function} animationFactory Factory function for creating new instance of an
1781            *                                    animation.
1782            * @description
1783            *
1784            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1785            *
1786            *
1787            * Defines an animation hook that can be later used with
1788            * {@link ngAnimate.$animate $animate} service and directives that use this service.
1789            *
1790            * ```js
1791            * module.animation('.animation-name', function($inject1, $inject2) {
1792            *   return {
1793            *     eventName : function(element, done) {
1794            *       //code to run the animation
1795            *       //once complete, then run done()
1796            *       return function cancellationFunction(element) {
1797            *         //code to cancel the animation
1798            *       }
1799            *     }
1800            *   }
1801            * })
1802            * ```
1803            *
1804            * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1805            * {@link ngAnimate ngAnimate module} for more information.
1806            */
1807           animation: invokeLater('$animateProvider', 'register'),
1808
1809           /**
1810            * @ngdoc method
1811            * @name angular.Module#filter
1812            * @module ng
1813            * @param {string} name Filter name.
1814            * @param {Function} filterFactory Factory function for creating new instance of filter.
1815            * @description
1816            * See {@link ng.$filterProvider#register $filterProvider.register()}.
1817            */
1818           filter: invokeLater('$filterProvider', 'register'),
1819
1820           /**
1821            * @ngdoc method
1822            * @name angular.Module#controller
1823            * @module ng
1824            * @param {string|Object} name Controller name, or an object map of controllers where the
1825            *    keys are the names and the values are the constructors.
1826            * @param {Function} constructor Controller constructor function.
1827            * @description
1828            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1829            */
1830           controller: invokeLater('$controllerProvider', 'register'),
1831
1832           /**
1833            * @ngdoc method
1834            * @name angular.Module#directive
1835            * @module ng
1836            * @param {string|Object} name Directive name, or an object map of directives where the
1837            *    keys are the names and the values are the factories.
1838            * @param {Function} directiveFactory Factory function for creating new instance of
1839            * directives.
1840            * @description
1841            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1842            */
1843           directive: invokeLater('$compileProvider', 'directive'),
1844
1845           /**
1846            * @ngdoc method
1847            * @name angular.Module#config
1848            * @module ng
1849            * @param {Function} configFn Execute this function on module load. Useful for service
1850            *    configuration.
1851            * @description
1852            * Use this method to register work which needs to be performed on module loading.
1853            * For more about how to configure services, see
1854            * {@link providers#providers_provider-recipe Provider Recipe}.
1855            */
1856           config: config,
1857
1858           /**
1859            * @ngdoc method
1860            * @name angular.Module#run
1861            * @module ng
1862            * @param {Function} initializationFn Execute this function after injector creation.
1863            *    Useful for application initialization.
1864            * @description
1865            * Use this method to register work which should be performed when the injector is done
1866            * loading all modules.
1867            */
1868           run: function(block) {
1869             runBlocks.push(block);
1870             return this;
1871           }
1872         };
1873
1874         if (configFn) {
1875           config(configFn);
1876         }
1877
1878         return  moduleInstance;
1879
1880         /**
1881          * @param {string} provider
1882          * @param {string} method
1883          * @param {String=} insertMethod
1884          * @returns {angular.Module}
1885          */
1886         function invokeLater(provider, method, insertMethod) {
1887           return function() {
1888             invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1889             return moduleInstance;
1890           };
1891         }
1892       });
1893     };
1894   });
1895
1896 }
1897
1898 /* global angularModule: true,
1899   version: true,
1900
1901   $LocaleProvider,
1902   $CompileProvider,
1903
1904     htmlAnchorDirective,
1905     inputDirective,
1906     inputDirective,
1907     formDirective,
1908     scriptDirective,
1909     selectDirective,
1910     styleDirective,
1911     optionDirective,
1912     ngBindDirective,
1913     ngBindHtmlDirective,
1914     ngBindTemplateDirective,
1915     ngClassDirective,
1916     ngClassEvenDirective,
1917     ngClassOddDirective,
1918     ngCspDirective,
1919     ngCloakDirective,
1920     ngControllerDirective,
1921     ngFormDirective,
1922     ngHideDirective,
1923     ngIfDirective,
1924     ngIncludeDirective,
1925     ngIncludeFillContentDirective,
1926     ngInitDirective,
1927     ngNonBindableDirective,
1928     ngPluralizeDirective,
1929     ngRepeatDirective,
1930     ngShowDirective,
1931     ngStyleDirective,
1932     ngSwitchDirective,
1933     ngSwitchWhenDirective,
1934     ngSwitchDefaultDirective,
1935     ngOptionsDirective,
1936     ngTranscludeDirective,
1937     ngModelDirective,
1938     ngListDirective,
1939     ngChangeDirective,
1940     requiredDirective,
1941     requiredDirective,
1942     ngValueDirective,
1943     ngAttributeAliasDirectives,
1944     ngEventDirectives,
1945
1946     $AnchorScrollProvider,
1947     $AnimateProvider,
1948     $BrowserProvider,
1949     $CacheFactoryProvider,
1950     $ControllerProvider,
1951     $DocumentProvider,
1952     $ExceptionHandlerProvider,
1953     $FilterProvider,
1954     $InterpolateProvider,
1955     $IntervalProvider,
1956     $HttpProvider,
1957     $HttpBackendProvider,
1958     $LocationProvider,
1959     $LogProvider,
1960     $ParseProvider,
1961     $RootScopeProvider,
1962     $QProvider,
1963     $$SanitizeUriProvider,
1964     $SceProvider,
1965     $SceDelegateProvider,
1966     $SnifferProvider,
1967     $TemplateCacheProvider,
1968     $TimeoutProvider,
1969     $$RAFProvider,
1970     $$AsyncCallbackProvider,
1971     $WindowProvider
1972 */
1973
1974
1975 /**
1976  * @ngdoc object
1977  * @name angular.version
1978  * @module ng
1979  * @description
1980  * An object that contains information about the current AngularJS version. This object has the
1981  * following properties:
1982  *
1983  * - `full` – `{string}` – Full version string, such as "0.9.18".
1984  * - `major` – `{number}` – Major version number, such as "0".
1985  * - `minor` – `{number}` – Minor version number, such as "9".
1986  * - `dot` – `{number}` – Dot version number, such as "18".
1987  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1988  */
1989 var version = {
1990   full: '1.2.25',    // all of these placeholder strings will be replaced by grunt's
1991   major: 1,    // package task
1992   minor: 2,
1993   dot: 25,
1994   codeName: 'hypnotic-gesticulation'
1995 };
1996
1997
1998 function publishExternalAPI(angular){
1999   extend(angular, {
2000     'bootstrap': bootstrap,
2001     'copy': copy,
2002     'extend': extend,
2003     'equals': equals,
2004     'element': jqLite,
2005     'forEach': forEach,
2006     'injector': createInjector,
2007     'noop': noop,
2008     'bind': bind,
2009     'toJson': toJson,
2010     'fromJson': fromJson,
2011     'identity': identity,
2012     'isUndefined': isUndefined,
2013     'isDefined': isDefined,
2014     'isString': isString,
2015     'isFunction': isFunction,
2016     'isObject': isObject,
2017     'isNumber': isNumber,
2018     'isElement': isElement,
2019     'isArray': isArray,
2020     'version': version,
2021     'isDate': isDate,
2022     'lowercase': lowercase,
2023     'uppercase': uppercase,
2024     'callbacks': {counter: 0},
2025     '$$minErr': minErr,
2026     '$$csp': csp
2027   });
2028
2029   angularModule = setupModuleLoader(window);
2030   try {
2031     angularModule('ngLocale');
2032   } catch (e) {
2033     angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2034   }
2035
2036   angularModule('ng', ['ngLocale'], ['$provide',
2037     function ngModule($provide) {
2038       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2039       $provide.provider({
2040         $$sanitizeUri: $$SanitizeUriProvider
2041       });
2042       $provide.provider('$compile', $CompileProvider).
2043         directive({
2044             a: htmlAnchorDirective,
2045             input: inputDirective,
2046             textarea: inputDirective,
2047             form: formDirective,
2048             script: scriptDirective,
2049             select: selectDirective,
2050             style: styleDirective,
2051             option: optionDirective,
2052             ngBind: ngBindDirective,
2053             ngBindHtml: ngBindHtmlDirective,
2054             ngBindTemplate: ngBindTemplateDirective,
2055             ngClass: ngClassDirective,
2056             ngClassEven: ngClassEvenDirective,
2057             ngClassOdd: ngClassOddDirective,
2058             ngCloak: ngCloakDirective,
2059             ngController: ngControllerDirective,
2060             ngForm: ngFormDirective,
2061             ngHide: ngHideDirective,
2062             ngIf: ngIfDirective,
2063             ngInclude: ngIncludeDirective,
2064             ngInit: ngInitDirective,
2065             ngNonBindable: ngNonBindableDirective,
2066             ngPluralize: ngPluralizeDirective,
2067             ngRepeat: ngRepeatDirective,
2068             ngShow: ngShowDirective,
2069             ngStyle: ngStyleDirective,
2070             ngSwitch: ngSwitchDirective,
2071             ngSwitchWhen: ngSwitchWhenDirective,
2072             ngSwitchDefault: ngSwitchDefaultDirective,
2073             ngOptions: ngOptionsDirective,
2074             ngTransclude: ngTranscludeDirective,
2075             ngModel: ngModelDirective,
2076             ngList: ngListDirective,
2077             ngChange: ngChangeDirective,
2078             required: requiredDirective,
2079             ngRequired: requiredDirective,
2080             ngValue: ngValueDirective
2081         }).
2082         directive({
2083           ngInclude: ngIncludeFillContentDirective
2084         }).
2085         directive(ngAttributeAliasDirectives).
2086         directive(ngEventDirectives);
2087       $provide.provider({
2088         $anchorScroll: $AnchorScrollProvider,
2089         $animate: $AnimateProvider,
2090         $browser: $BrowserProvider,
2091         $cacheFactory: $CacheFactoryProvider,
2092         $controller: $ControllerProvider,
2093         $document: $DocumentProvider,
2094         $exceptionHandler: $ExceptionHandlerProvider,
2095         $filter: $FilterProvider,
2096         $interpolate: $InterpolateProvider,
2097         $interval: $IntervalProvider,
2098         $http: $HttpProvider,
2099         $httpBackend: $HttpBackendProvider,
2100         $location: $LocationProvider,
2101         $log: $LogProvider,
2102         $parse: $ParseProvider,
2103         $rootScope: $RootScopeProvider,
2104         $q: $QProvider,
2105         $sce: $SceProvider,
2106         $sceDelegate: $SceDelegateProvider,
2107         $sniffer: $SnifferProvider,
2108         $templateCache: $TemplateCacheProvider,
2109         $timeout: $TimeoutProvider,
2110         $window: $WindowProvider,
2111         $$rAF: $$RAFProvider,
2112         $$asyncCallback : $$AsyncCallbackProvider
2113       });
2114     }
2115   ]);
2116 }
2117
2118 /* global JQLitePrototype: true,
2119   addEventListenerFn: true,
2120   removeEventListenerFn: true,
2121   BOOLEAN_ATTR: true
2122 */
2123
2124 //////////////////////////////////
2125 //JQLite
2126 //////////////////////////////////
2127
2128 /**
2129  * @ngdoc function
2130  * @name angular.element
2131  * @module ng
2132  * @kind function
2133  *
2134  * @description
2135  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2136  *
2137  * If jQuery is available, `angular.element` is an alias for the
2138  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2139  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2140  *
2141  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2142  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2143  * commonly needed functionality with the goal of having a very small footprint.</div>
2144  *
2145  * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2146  *
2147  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2148  * jqLite; they are never raw DOM references.</div>
2149  *
2150  * ## Angular's jqLite
2151  * jqLite provides only the following jQuery methods:
2152  *
2153  * - [`addClass()`](http://api.jquery.com/addClass/)
2154  * - [`after()`](http://api.jquery.com/after/)
2155  * - [`append()`](http://api.jquery.com/append/)
2156  * - [`attr()`](http://api.jquery.com/attr/)
2157  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2158  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2159  * - [`clone()`](http://api.jquery.com/clone/)
2160  * - [`contents()`](http://api.jquery.com/contents/)
2161  * - [`css()`](http://api.jquery.com/css/)
2162  * - [`data()`](http://api.jquery.com/data/)
2163  * - [`empty()`](http://api.jquery.com/empty/)
2164  * - [`eq()`](http://api.jquery.com/eq/)
2165  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2166  * - [`hasClass()`](http://api.jquery.com/hasClass/)
2167  * - [`html()`](http://api.jquery.com/html/)
2168  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2169  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2170  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2171  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2172  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2173  * - [`prepend()`](http://api.jquery.com/prepend/)
2174  * - [`prop()`](http://api.jquery.com/prop/)
2175  * - [`ready()`](http://api.jquery.com/ready/)
2176  * - [`remove()`](http://api.jquery.com/remove/)
2177  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2178  * - [`removeClass()`](http://api.jquery.com/removeClass/)
2179  * - [`removeData()`](http://api.jquery.com/removeData/)
2180  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2181  * - [`text()`](http://api.jquery.com/text/)
2182  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2183  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2184  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2185  * - [`val()`](http://api.jquery.com/val/)
2186  * - [`wrap()`](http://api.jquery.com/wrap/)
2187  *
2188  * ## jQuery/jqLite Extras
2189  * Angular also provides the following additional methods and events to both jQuery and jqLite:
2190  *
2191  * ### Events
2192  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2193  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2194  *    element before it is removed.
2195  *
2196  * ### Methods
2197  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2198  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2199  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2200  *   `'ngModel'`).
2201  * - `injector()` - retrieves the injector of the current element or its parent.
2202  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2203  *   element or its parent.
2204  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2205  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2206  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2207  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2208  *   parent element is reached.
2209  *
2210  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2211  * @returns {Object} jQuery object.
2212  */
2213
2214 JQLite.expando = 'ng339';
2215
2216 var jqCache = JQLite.cache = {},
2217     jqId = 1,
2218     addEventListenerFn = (window.document.addEventListener
2219       ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2220       : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2221     removeEventListenerFn = (window.document.removeEventListener
2222       ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2223       : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2224
2225 /*
2226  * !!! This is an undocumented "private" function !!!
2227  */
2228 var jqData = JQLite._data = function(node) {
2229   //jQuery always returns an object on cache miss
2230   return this.cache[node[this.expando]] || {};
2231 };
2232
2233 function jqNextId() { return ++jqId; }
2234
2235
2236 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2237 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2238 var jqLiteMinErr = minErr('jqLite');
2239
2240 /**
2241  * Converts snake_case to camelCase.
2242  * Also there is special case for Moz prefix starting with upper case letter.
2243  * @param name Name to normalize
2244  */
2245 function camelCase(name) {
2246   return name.
2247     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2248       return offset ? letter.toUpperCase() : letter;
2249     }).
2250     replace(MOZ_HACK_REGEXP, 'Moz$1');
2251 }
2252
2253 /////////////////////////////////////////////
2254 // jQuery mutation patch
2255 //
2256 // In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2257 // $destroy event on all DOM nodes being removed.
2258 //
2259 /////////////////////////////////////////////
2260
2261 function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2262   var originalJqFn = jQuery.fn[name];
2263   originalJqFn = originalJqFn.$original || originalJqFn;
2264   removePatch.$original = originalJqFn;
2265   jQuery.fn[name] = removePatch;
2266
2267   function removePatch(param) {
2268     // jshint -W040
2269     var list = filterElems && param ? [this.filter(param)] : [this],
2270         fireEvent = dispatchThis,
2271         set, setIndex, setLength,
2272         element, childIndex, childLength, children;
2273
2274     if (!getterIfNoArguments || param != null) {
2275       while(list.length) {
2276         set = list.shift();
2277         for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2278           element = jqLite(set[setIndex]);
2279           if (fireEvent) {
2280             element.triggerHandler('$destroy');
2281           } else {
2282             fireEvent = !fireEvent;
2283           }
2284           for(childIndex = 0, childLength = (children = element.children()).length;
2285               childIndex < childLength;
2286               childIndex++) {
2287             list.push(jQuery(children[childIndex]));
2288           }
2289         }
2290       }
2291     }
2292     return originalJqFn.apply(this, arguments);
2293   }
2294 }
2295
2296 var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2297 var HTML_REGEXP = /<|&#?\w+;/;
2298 var TAG_NAME_REGEXP = /<([\w:]+)/;
2299 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2300
2301 var wrapMap = {
2302   'option': [1, '<select multiple="multiple">', '</select>'],
2303
2304   'thead': [1, '<table>', '</table>'],
2305   'col': [2, '<table><colgroup>', '</colgroup></table>'],
2306   'tr': [2, '<table><tbody>', '</tbody></table>'],
2307   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2308   '_default': [0, "", ""]
2309 };
2310
2311 wrapMap.optgroup = wrapMap.option;
2312 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2313 wrapMap.th = wrapMap.td;
2314
2315 function jqLiteIsTextNode(html) {
2316   return !HTML_REGEXP.test(html);
2317 }
2318
2319 function jqLiteBuildFragment(html, context) {
2320   var elem, tmp, tag, wrap,
2321       fragment = context.createDocumentFragment(),
2322       nodes = [], i, j, jj;
2323
2324   if (jqLiteIsTextNode(html)) {
2325     // Convert non-html into a text node
2326     nodes.push(context.createTextNode(html));
2327   } else {
2328     tmp = fragment.appendChild(context.createElement('div'));
2329     // Convert html into DOM nodes
2330     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2331     wrap = wrapMap[tag] || wrapMap._default;
2332     tmp.innerHTML = '<div>&#160;</div>' +
2333       wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2334     tmp.removeChild(tmp.firstChild);
2335
2336     // Descend through wrappers to the right content
2337     i = wrap[0];
2338     while (i--) {
2339       tmp = tmp.lastChild;
2340     }
2341
2342     for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
2343
2344     tmp = fragment.firstChild;
2345     tmp.textContent = "";
2346   }
2347
2348   // Remove wrapper from fragment
2349   fragment.textContent = "";
2350   fragment.innerHTML = ""; // Clear inner HTML
2351   return nodes;
2352 }
2353
2354 function jqLiteParseHTML(html, context) {
2355   context = context || document;
2356   var parsed;
2357
2358   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2359     return [context.createElement(parsed[1])];
2360   }
2361
2362   return jqLiteBuildFragment(html, context);
2363 }
2364
2365 /////////////////////////////////////////////
2366 function JQLite(element) {
2367   if (element instanceof JQLite) {
2368     return element;
2369   }
2370   if (isString(element)) {
2371     element = trim(element);
2372   }
2373   if (!(this instanceof JQLite)) {
2374     if (isString(element) && element.charAt(0) != '<') {
2375       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2376     }
2377     return new JQLite(element);
2378   }
2379
2380   if (isString(element)) {
2381     jqLiteAddNodes(this, jqLiteParseHTML(element));
2382     var fragment = jqLite(document.createDocumentFragment());
2383     fragment.append(this);
2384   } else {
2385     jqLiteAddNodes(this, element);
2386   }
2387 }
2388
2389 function jqLiteClone(element) {
2390   return element.cloneNode(true);
2391 }
2392
2393 function jqLiteDealoc(element){
2394   jqLiteRemoveData(element);
2395   for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2396     jqLiteDealoc(children[i]);
2397   }
2398 }
2399
2400 function jqLiteOff(element, type, fn, unsupported) {
2401   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2402
2403   var events = jqLiteExpandoStore(element, 'events'),
2404       handle = jqLiteExpandoStore(element, 'handle');
2405
2406   if (!handle) return; //no listeners registered
2407
2408   if (isUndefined(type)) {
2409     forEach(events, function(eventHandler, type) {
2410       removeEventListenerFn(element, type, eventHandler);
2411       delete events[type];
2412     });
2413   } else {
2414     forEach(type.split(' '), function(type) {
2415       if (isUndefined(fn)) {
2416         removeEventListenerFn(element, type, events[type]);
2417         delete events[type];
2418       } else {
2419         arrayRemove(events[type] || [], fn);
2420       }
2421     });
2422   }
2423 }
2424
2425 function jqLiteRemoveData(element, name) {
2426   var expandoId = element.ng339,
2427       expandoStore = jqCache[expandoId];
2428
2429   if (expandoStore) {
2430     if (name) {
2431       delete jqCache[expandoId].data[name];
2432       return;
2433     }
2434
2435     if (expandoStore.handle) {
2436       expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2437       jqLiteOff(element);
2438     }
2439     delete jqCache[expandoId];
2440     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2441   }
2442 }
2443
2444 function jqLiteExpandoStore(element, key, value) {
2445   var expandoId = element.ng339,
2446       expandoStore = jqCache[expandoId || -1];
2447
2448   if (isDefined(value)) {
2449     if (!expandoStore) {
2450       element.ng339 = expandoId = jqNextId();
2451       expandoStore = jqCache[expandoId] = {};
2452     }
2453     expandoStore[key] = value;
2454   } else {
2455     return expandoStore && expandoStore[key];
2456   }
2457 }
2458
2459 function jqLiteData(element, key, value) {
2460   var data = jqLiteExpandoStore(element, 'data'),
2461       isSetter = isDefined(value),
2462       keyDefined = !isSetter && isDefined(key),
2463       isSimpleGetter = keyDefined && !isObject(key);
2464
2465   if (!data && !isSimpleGetter) {
2466     jqLiteExpandoStore(element, 'data', data = {});
2467   }
2468
2469   if (isSetter) {
2470     data[key] = value;
2471   } else {
2472     if (keyDefined) {
2473       if (isSimpleGetter) {
2474         // don't create data in this case.
2475         return data && data[key];
2476       } else {
2477         extend(data, key);
2478       }
2479     } else {
2480       return data;
2481     }
2482   }
2483 }
2484
2485 function jqLiteHasClass(element, selector) {
2486   if (!element.getAttribute) return false;
2487   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2488       indexOf( " " + selector + " " ) > -1);
2489 }
2490
2491 function jqLiteRemoveClass(element, cssClasses) {
2492   if (cssClasses && element.setAttribute) {
2493     forEach(cssClasses.split(' '), function(cssClass) {
2494       element.setAttribute('class', trim(
2495           (" " + (element.getAttribute('class') || '') + " ")
2496           .replace(/[\n\t]/g, " ")
2497           .replace(" " + trim(cssClass) + " ", " "))
2498       );
2499     });
2500   }
2501 }
2502
2503 function jqLiteAddClass(element, cssClasses) {
2504   if (cssClasses && element.setAttribute) {
2505     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2506                             .replace(/[\n\t]/g, " ");
2507
2508     forEach(cssClasses.split(' '), function(cssClass) {
2509       cssClass = trim(cssClass);
2510       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2511         existingClasses += cssClass + ' ';
2512       }
2513     });
2514
2515     element.setAttribute('class', trim(existingClasses));
2516   }
2517 }
2518
2519 function jqLiteAddNodes(root, elements) {
2520   if (elements) {
2521     elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2522       ? elements
2523       : [ elements ];
2524     for(var i=0; i < elements.length; i++) {
2525       root.push(elements[i]);
2526     }
2527   }
2528 }
2529
2530 function jqLiteController(element, name) {
2531   return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2532 }
2533
2534 function jqLiteInheritedData(element, name, value) {
2535   // if element is the document object work with the html element instead
2536   // this makes $(document).scope() possible
2537   if(element.nodeType == 9) {
2538     element = element.documentElement;
2539   }
2540   var names = isArray(name) ? name : [name];
2541
2542   while (element) {
2543     for (var i = 0, ii = names.length; i < ii; i++) {
2544       if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2545     }
2546
2547     // If dealing with a document fragment node with a host element, and no parent, use the host
2548     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2549     // to lookup parent controllers.
2550     element = element.parentNode || (element.nodeType === 11 && element.host);
2551   }
2552 }
2553
2554 function jqLiteEmpty(element) {
2555   for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2556     jqLiteDealoc(childNodes[i]);
2557   }
2558   while (element.firstChild) {
2559     element.removeChild(element.firstChild);
2560   }
2561 }
2562
2563 //////////////////////////////////////////
2564 // Functions which are declared directly.
2565 //////////////////////////////////////////
2566 var JQLitePrototype = JQLite.prototype = {
2567   ready: function(fn) {
2568     var fired = false;
2569
2570     function trigger() {
2571       if (fired) return;
2572       fired = true;
2573       fn();
2574     }
2575
2576     // check if document already is loaded
2577     if (document.readyState === 'complete'){
2578       setTimeout(trigger);
2579     } else {
2580       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2581       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2582       // jshint -W064
2583       JQLite(window).on('load', trigger); // fallback to window.onload for others
2584       // jshint +W064
2585     }
2586   },
2587   toString: function() {
2588     var value = [];
2589     forEach(this, function(e){ value.push('' + e);});
2590     return '[' + value.join(', ') + ']';
2591   },
2592
2593   eq: function(index) {
2594       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2595   },
2596
2597   length: 0,
2598   push: push,
2599   sort: [].sort,
2600   splice: [].splice
2601 };
2602
2603 //////////////////////////////////////////
2604 // Functions iterating getter/setters.
2605 // these functions return self on setter and
2606 // value on get.
2607 //////////////////////////////////////////
2608 var BOOLEAN_ATTR = {};
2609 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2610   BOOLEAN_ATTR[lowercase(value)] = value;
2611 });
2612 var BOOLEAN_ELEMENTS = {};
2613 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2614   BOOLEAN_ELEMENTS[uppercase(value)] = true;
2615 });
2616
2617 function getBooleanAttrName(element, name) {
2618   // check dom last since we will most likely fail on name
2619   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2620
2621   // booleanAttr is here twice to minimize DOM access
2622   return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2623 }
2624
2625 forEach({
2626   data: jqLiteData,
2627   removeData: jqLiteRemoveData
2628 }, function(fn, name) {
2629   JQLite[name] = fn;
2630 });
2631
2632 forEach({
2633   data: jqLiteData,
2634   inheritedData: jqLiteInheritedData,
2635
2636   scope: function(element) {
2637     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2638     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2639   },
2640
2641   isolateScope: function(element) {
2642     // Can't use jqLiteData here directly so we stay compatible with jQuery!
2643     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2644   },
2645
2646   controller: jqLiteController,
2647
2648   injector: function(element) {
2649     return jqLiteInheritedData(element, '$injector');
2650   },
2651
2652   removeAttr: function(element,name) {
2653     element.removeAttribute(name);
2654   },
2655
2656   hasClass: jqLiteHasClass,
2657
2658   css: function(element, name, value) {
2659     name = camelCase(name);
2660
2661     if (isDefined(value)) {
2662       element.style[name] = value;
2663     } else {
2664       var val;
2665
2666       if (msie <= 8) {
2667         // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2668         val = element.currentStyle && element.currentStyle[name];
2669         if (val === '') val = 'auto';
2670       }
2671
2672       val = val || element.style[name];
2673
2674       if (msie <= 8) {
2675         // jquery weirdness :-/
2676         val = (val === '') ? undefined : val;
2677       }
2678
2679       return  val;
2680     }
2681   },
2682
2683   attr: function(element, name, value){
2684     var lowercasedName = lowercase(name);
2685     if (BOOLEAN_ATTR[lowercasedName]) {
2686       if (isDefined(value)) {
2687         if (!!value) {
2688           element[name] = true;
2689           element.setAttribute(name, lowercasedName);
2690         } else {
2691           element[name] = false;
2692           element.removeAttribute(lowercasedName);
2693         }
2694       } else {
2695         return (element[name] ||
2696                  (element.attributes.getNamedItem(name)|| noop).specified)
2697                ? lowercasedName
2698                : undefined;
2699       }
2700     } else if (isDefined(value)) {
2701       element.setAttribute(name, value);
2702     } else if (element.getAttribute) {
2703       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2704       // some elements (e.g. Document) don't have get attribute, so return undefined
2705       var ret = element.getAttribute(name, 2);
2706       // normalize non-existing attributes to undefined (as jQuery)
2707       return ret === null ? undefined : ret;
2708     }
2709   },
2710
2711   prop: function(element, name, value) {
2712     if (isDefined(value)) {
2713       element[name] = value;
2714     } else {
2715       return element[name];
2716     }
2717   },
2718
2719   text: (function() {
2720     var NODE_TYPE_TEXT_PROPERTY = [];
2721     if (msie < 9) {
2722       NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2723       NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2724     } else {
2725       NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2726       NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2727     }
2728     getText.$dv = '';
2729     return getText;
2730
2731     function getText(element, value) {
2732       var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2733       if (isUndefined(value)) {
2734         return textProp ? element[textProp] : '';
2735       }
2736       element[textProp] = value;
2737     }
2738   })(),
2739
2740   val: function(element, value) {
2741     if (isUndefined(value)) {
2742       if (nodeName_(element) === 'SELECT' && element.multiple) {
2743         var result = [];
2744         forEach(element.options, function (option) {
2745           if (option.selected) {
2746             result.push(option.value || option.text);
2747           }
2748         });
2749         return result.length === 0 ? null : result;
2750       }
2751       return element.value;
2752     }
2753     element.value = value;
2754   },
2755
2756   html: function(element, value) {
2757     if (isUndefined(value)) {
2758       return element.innerHTML;
2759     }
2760     for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2761       jqLiteDealoc(childNodes[i]);
2762     }
2763     element.innerHTML = value;
2764   },
2765
2766   empty: jqLiteEmpty
2767 }, function(fn, name){
2768   /**
2769    * Properties: writes return selection, reads return first value
2770    */
2771   JQLite.prototype[name] = function(arg1, arg2) {
2772     var i, key;
2773     var nodeCount = this.length;
2774
2775     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2776     // in a way that survives minification.
2777     // jqLiteEmpty takes no arguments but is a setter.
2778     if (fn !== jqLiteEmpty &&
2779         (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2780       if (isObject(arg1)) {
2781
2782         // we are a write, but the object properties are the key/values
2783         for (i = 0; i < nodeCount; i++) {
2784           if (fn === jqLiteData) {
2785             // data() takes the whole object in jQuery
2786             fn(this[i], arg1);
2787           } else {
2788             for (key in arg1) {
2789               fn(this[i], key, arg1[key]);
2790             }
2791           }
2792         }
2793         // return self for chaining
2794         return this;
2795       } else {
2796         // we are a read, so read the first child.
2797         // TODO: do we still need this?
2798         var value = fn.$dv;
2799         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2800         var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2801         for (var j = 0; j < jj; j++) {
2802           var nodeValue = fn(this[j], arg1, arg2);
2803           value = value ? value + nodeValue : nodeValue;
2804         }
2805         return value;
2806       }
2807     } else {
2808       // we are a write, so apply to all children
2809       for (i = 0; i < nodeCount; i++) {
2810         fn(this[i], arg1, arg2);
2811       }
2812       // return self for chaining
2813       return this;
2814     }
2815   };
2816 });
2817
2818 function createEventHandler(element, events) {
2819   var eventHandler = function (event, type) {
2820     if (!event.preventDefault) {
2821       event.preventDefault = function() {
2822         event.returnValue = false; //ie
2823       };
2824     }
2825
2826     if (!event.stopPropagation) {
2827       event.stopPropagation = function() {
2828         event.cancelBubble = true; //ie
2829       };
2830     }
2831
2832     if (!event.target) {
2833       event.target = event.srcElement || document;
2834     }
2835
2836     if (isUndefined(event.defaultPrevented)) {
2837       var prevent = event.preventDefault;
2838       event.preventDefault = function() {
2839         event.defaultPrevented = true;
2840         prevent.call(event);
2841       };
2842       event.defaultPrevented = false;
2843     }
2844
2845     event.isDefaultPrevented = function() {
2846       return event.defaultPrevented || event.returnValue === false;
2847     };
2848
2849     // Copy event handlers in case event handlers array is modified during execution.
2850     var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2851
2852     forEach(eventHandlersCopy, function(fn) {
2853       fn.call(element, event);
2854     });
2855
2856     // Remove monkey-patched methods (IE),
2857     // as they would cause memory leaks in IE8.
2858     if (msie <= 8) {
2859       // IE7/8 does not allow to delete property on native object
2860       event.preventDefault = null;
2861       event.stopPropagation = null;
2862       event.isDefaultPrevented = null;
2863     } else {
2864       // It shouldn't affect normal browsers (native methods are defined on prototype).
2865       delete event.preventDefault;
2866       delete event.stopPropagation;
2867       delete event.isDefaultPrevented;
2868     }
2869   };
2870   eventHandler.elem = element;
2871   return eventHandler;
2872 }
2873
2874 //////////////////////////////////////////
2875 // Functions iterating traversal.
2876 // These functions chain results into a single
2877 // selector.
2878 //////////////////////////////////////////
2879 forEach({
2880   removeData: jqLiteRemoveData,
2881
2882   dealoc: jqLiteDealoc,
2883
2884   on: function onFn(element, type, fn, unsupported){
2885     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2886
2887     var events = jqLiteExpandoStore(element, 'events'),
2888         handle = jqLiteExpandoStore(element, 'handle');
2889
2890     if (!events) jqLiteExpandoStore(element, 'events', events = {});
2891     if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2892
2893     forEach(type.split(' '), function(type){
2894       var eventFns = events[type];
2895
2896       if (!eventFns) {
2897         if (type == 'mouseenter' || type == 'mouseleave') {
2898           var contains = document.body.contains || document.body.compareDocumentPosition ?
2899           function( a, b ) {
2900             // jshint bitwise: false
2901             var adown = a.nodeType === 9 ? a.documentElement : a,
2902             bup = b && b.parentNode;
2903             return a === bup || !!( bup && bup.nodeType === 1 && (
2904               adown.contains ?
2905               adown.contains( bup ) :
2906               a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2907               ));
2908             } :
2909             function( a, b ) {
2910               if ( b ) {
2911                 while ( (b = b.parentNode) ) {
2912                   if ( b === a ) {
2913                     return true;
2914                   }
2915                 }
2916               }
2917               return false;
2918             };
2919
2920           events[type] = [];
2921
2922           // Refer to jQuery's implementation of mouseenter & mouseleave
2923           // Read about mouseenter and mouseleave:
2924           // http://www.quirksmode.org/js/events_mouse.html#link8
2925           var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2926
2927           onFn(element, eventmap[type], function(event) {
2928             var target = this, related = event.relatedTarget;
2929             // For mousenter/leave call the handler if related is outside the target.
2930             // NB: No relatedTarget if the mouse left/entered the browser window
2931             if ( !related || (related !== target && !contains(target, related)) ){
2932               handle(event, type);
2933             }
2934           });
2935
2936         } else {
2937           addEventListenerFn(element, type, handle);
2938           events[type] = [];
2939         }
2940         eventFns = events[type];
2941       }
2942       eventFns.push(fn);
2943     });
2944   },
2945
2946   off: jqLiteOff,
2947
2948   one: function(element, type, fn) {
2949     element = jqLite(element);
2950
2951     //add the listener twice so that when it is called
2952     //you can remove the original function and still be
2953     //able to call element.off(ev, fn) normally
2954     element.on(type, function onFn() {
2955       element.off(type, fn);
2956       element.off(type, onFn);
2957     });
2958     element.on(type, fn);
2959   },
2960
2961   replaceWith: function(element, replaceNode) {
2962     var index, parent = element.parentNode;
2963     jqLiteDealoc(element);
2964     forEach(new JQLite(replaceNode), function(node){
2965       if (index) {
2966         parent.insertBefore(node, index.nextSibling);
2967       } else {
2968         parent.replaceChild(node, element);
2969       }
2970       index = node;
2971     });
2972   },
2973
2974   children: function(element) {
2975     var children = [];
2976     forEach(element.childNodes, function(element){
2977       if (element.nodeType === 1)
2978         children.push(element);
2979     });
2980     return children;
2981   },
2982
2983   contents: function(element) {
2984     return element.contentDocument || element.childNodes || [];
2985   },
2986
2987   append: function(element, node) {
2988     forEach(new JQLite(node), function(child){
2989       if (element.nodeType === 1 || element.nodeType === 11) {
2990         element.appendChild(child);
2991       }
2992     });
2993   },
2994
2995   prepend: function(element, node) {
2996     if (element.nodeType === 1) {
2997       var index = element.firstChild;
2998       forEach(new JQLite(node), function(child){
2999         element.insertBefore(child, index);
3000       });
3001     }
3002   },
3003
3004   wrap: function(element, wrapNode) {
3005     wrapNode = jqLite(wrapNode)[0];
3006     var parent = element.parentNode;
3007     if (parent) {
3008       parent.replaceChild(wrapNode, element);
3009     }
3010     wrapNode.appendChild(element);
3011   },
3012
3013   remove: function(element) {
3014     jqLiteDealoc(element);
3015     var parent = element.parentNode;
3016     if (parent) parent.removeChild(element);
3017   },
3018
3019   after: function(element, newElement) {
3020     var index = element, parent = element.parentNode;
3021     forEach(new JQLite(newElement), function(node){
3022       parent.insertBefore(node, index.nextSibling);
3023       index = node;
3024     });
3025   },
3026
3027   addClass: jqLiteAddClass,
3028   removeClass: jqLiteRemoveClass,
3029
3030   toggleClass: function(element, selector, condition) {
3031     if (selector) {
3032       forEach(selector.split(' '), function(className){
3033         var classCondition = condition;
3034         if (isUndefined(classCondition)) {
3035           classCondition = !jqLiteHasClass(element, className);
3036         }
3037         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3038       });
3039     }
3040   },
3041
3042   parent: function(element) {
3043     var parent = element.parentNode;
3044     return parent && parent.nodeType !== 11 ? parent : null;
3045   },
3046
3047   next: function(element) {
3048     if (element.nextElementSibling) {
3049       return element.nextElementSibling;
3050     }
3051
3052     // IE8 doesn't have nextElementSibling
3053     var elm = element.nextSibling;
3054     while (elm != null && elm.nodeType !== 1) {
3055       elm = elm.nextSibling;
3056     }
3057     return elm;
3058   },
3059
3060   find: function(element, selector) {
3061     if (element.getElementsByTagName) {
3062       return element.getElementsByTagName(selector);
3063     } else {
3064       return [];
3065     }
3066   },
3067
3068   clone: jqLiteClone,
3069
3070   triggerHandler: function(element, event, extraParameters) {
3071
3072     var dummyEvent, eventFnsCopy, handlerArgs;
3073     var eventName = event.type || event;
3074     var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
3075
3076     if (eventFns) {
3077
3078       // Create a dummy event to pass to the handlers
3079       dummyEvent = {
3080         preventDefault: function() { this.defaultPrevented = true; },
3081         isDefaultPrevented: function() { return this.defaultPrevented === true; },
3082         stopPropagation: noop,
3083         type: eventName,
3084         target: element
3085       };
3086
3087       // If a custom event was provided then extend our dummy event with it
3088       if (event.type) {
3089         dummyEvent = extend(dummyEvent, event);
3090       }
3091
3092       // Copy event handlers in case event handlers array is modified during execution.
3093       eventFnsCopy = shallowCopy(eventFns);
3094       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3095
3096       forEach(eventFnsCopy, function(fn) {
3097         fn.apply(element, handlerArgs);
3098       });
3099
3100     }
3101   }
3102 }, function(fn, name){
3103   /**
3104    * chaining functions
3105    */
3106   JQLite.prototype[name] = function(arg1, arg2, arg3) {
3107     var value;
3108     for(var i=0; i < this.length; i++) {
3109       if (isUndefined(value)) {
3110         value = fn(this[i], arg1, arg2, arg3);
3111         if (isDefined(value)) {
3112           // any function which returns a value needs to be wrapped
3113           value = jqLite(value);
3114         }
3115       } else {
3116         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3117       }
3118     }
3119     return isDefined(value) ? value : this;
3120   };
3121
3122   // bind legacy bind/unbind to on/off
3123   JQLite.prototype.bind = JQLite.prototype.on;
3124   JQLite.prototype.unbind = JQLite.prototype.off;
3125 });
3126
3127 /**
3128  * Computes a hash of an 'obj'.
3129  * Hash of a:
3130  *  string is string
3131  *  number is number as string
3132  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3133  *         that is also assigned to the $$hashKey property of the object.
3134  *
3135  * @param obj
3136  * @returns {string} hash string such that the same input will have the same hash string.
3137  *         The resulting string key is in 'type:hashKey' format.
3138  */
3139 function hashKey(obj, nextUidFn) {
3140   var objType = typeof obj,
3141       key;
3142
3143   if (objType == 'function' || (objType == 'object' && obj !== null)) {
3144     if (typeof (key = obj.$$hashKey) == 'function') {
3145       // must invoke on object to keep the right this
3146       key = obj.$$hashKey();
3147     } else if (key === undefined) {
3148       key = obj.$$hashKey = (nextUidFn || nextUid)();
3149     }
3150   } else {
3151     key = obj;
3152   }
3153
3154   return objType + ':' + key;
3155 }
3156
3157 /**
3158  * HashMap which can use objects as keys
3159  */
3160 function HashMap(array, isolatedUid) {
3161   if (isolatedUid) {
3162     var uid = 0;
3163     this.nextUid = function() {
3164       return ++uid;
3165     };
3166   }
3167   forEach(array, this.put, this);
3168 }
3169 HashMap.prototype = {
3170   /**
3171    * Store key value pair
3172    * @param key key to store can be any type
3173    * @param value value to store can be any type
3174    */
3175   put: function(key, value) {
3176     this[hashKey(key, this.nextUid)] = value;
3177   },
3178
3179   /**
3180    * @param key
3181    * @returns {Object} the value for the key
3182    */
3183   get: function(key) {
3184     return this[hashKey(key, this.nextUid)];
3185   },
3186
3187   /**
3188    * Remove the key/value pair
3189    * @param key
3190    */
3191   remove: function(key) {
3192     var value = this[key = hashKey(key, this.nextUid)];
3193     delete this[key];
3194     return value;
3195   }
3196 };
3197
3198 /**
3199  * @ngdoc function
3200  * @module ng
3201  * @name angular.injector
3202  * @kind function
3203  *
3204  * @description
3205  * Creates an injector function that can be used for retrieving services as well as for
3206  * dependency injection (see {@link guide/di dependency injection}).
3207  *
3208
3209  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3210  *        {@link angular.module}. The `ng` module must be explicitly added.
3211  * @returns {function()} Injector function. See {@link auto.$injector $injector}.
3212  *
3213  * @example
3214  * Typical usage
3215  * ```js
3216  *   // create an injector
3217  *   var $injector = angular.injector(['ng']);
3218  *
3219  *   // use the injector to kick off your application
3220  *   // use the type inference to auto inject arguments, or use implicit injection
3221  *   $injector.invoke(function($rootScope, $compile, $document){
3222  *     $compile($document)($rootScope);
3223  *     $rootScope.$digest();
3224  *   });
3225  * ```
3226  *
3227  * Sometimes you want to get access to the injector of a currently running Angular app
3228  * from outside Angular. Perhaps, you want to inject and compile some markup after the
3229  * application has been bootstrapped. You can do this using the extra `injector()` added
3230  * to JQuery/jqLite elements. See {@link angular.element}.
3231  *
3232  * *This is fairly rare but could be the case if a third party library is injecting the
3233  * markup.*
3234  *
3235  * In the following example a new block of HTML containing a `ng-controller`
3236  * directive is added to the end of the document body by JQuery. We then compile and link
3237  * it into the current AngularJS scope.
3238  *
3239  * ```js
3240  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3241  * $(document.body).append($div);
3242  *
3243  * angular.element(document).injector().invoke(function($compile) {
3244  *   var scope = angular.element($div).scope();
3245  *   $compile($div)(scope);
3246  * });
3247  * ```
3248  */
3249
3250
3251 /**
3252  * @ngdoc module
3253  * @name auto
3254  * @description
3255  *
3256  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3257  */
3258
3259 var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3260 var FN_ARG_SPLIT = /,/;
3261 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3262 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3263 var $injectorMinErr = minErr('$injector');
3264 function annotate(fn) {
3265   var $inject,
3266       fnText,
3267       argDecl,
3268       last;
3269
3270   if (typeof fn === 'function') {
3271     if (!($inject = fn.$inject)) {
3272       $inject = [];
3273       if (fn.length) {
3274         fnText = fn.toString().replace(STRIP_COMMENTS, '');
3275         argDecl = fnText.match(FN_ARGS);
3276         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3277           arg.replace(FN_ARG, function(all, underscore, name){
3278             $inject.push(name);
3279           });
3280         });
3281       }
3282       fn.$inject = $inject;
3283     }
3284   } else if (isArray(fn)) {
3285     last = fn.length - 1;
3286     assertArgFn(fn[last], 'fn');
3287     $inject = fn.slice(0, last);
3288   } else {
3289     assertArgFn(fn, 'fn', true);
3290   }
3291   return $inject;
3292 }
3293
3294 ///////////////////////////////////////
3295
3296 /**
3297  * @ngdoc service
3298  * @name $injector
3299  * @kind function
3300  *
3301  * @description
3302  *
3303  * `$injector` is used to retrieve object instances as defined by
3304  * {@link auto.$provide provider}, instantiate types, invoke methods,
3305  * and load modules.
3306  *
3307  * The following always holds true:
3308  *
3309  * ```js
3310  *   var $injector = angular.injector();
3311  *   expect($injector.get('$injector')).toBe($injector);
3312  *   expect($injector.invoke(function($injector){
3313  *     return $injector;
3314  *   }).toBe($injector);
3315  * ```
3316  *
3317  * # Injection Function Annotation
3318  *
3319  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3320  * following are all valid ways of annotating function with injection arguments and are equivalent.
3321  *
3322  * ```js
3323  *   // inferred (only works if code not minified/obfuscated)
3324  *   $injector.invoke(function(serviceA){});
3325  *
3326  *   // annotated
3327  *   function explicit(serviceA) {};
3328  *   explicit.$inject = ['serviceA'];
3329  *   $injector.invoke(explicit);
3330  *
3331  *   // inline
3332  *   $injector.invoke(['serviceA', function(serviceA){}]);
3333  * ```
3334  *
3335  * ## Inference
3336  *
3337  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3338  * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3339  * minification, and obfuscation tools since these tools change the argument names.
3340  *
3341  * ## `$inject` Annotation
3342  * By adding an `$inject` property onto a function the injection parameters can be specified.
3343  *
3344  * ## Inline
3345  * As an array of injection names, where the last item in the array is the function to call.
3346  */
3347
3348 /**
3349  * @ngdoc method
3350  * @name $injector#get
3351  *
3352  * @description
3353  * Return an instance of the service.
3354  *
3355  * @param {string} name The name of the instance to retrieve.
3356  * @return {*} The instance.
3357  */
3358
3359 /**
3360  * @ngdoc method
3361  * @name $injector#invoke
3362  *
3363  * @description
3364  * Invoke the method and supply the method arguments from the `$injector`.
3365  *
3366  * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3367  *   {@link guide/di $inject Annotation} rules.
3368  * @param {Object=} self The `this` for the invoked method.
3369  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3370  *                         object first, before the `$injector` is consulted.
3371  * @returns {*} the value returned by the invoked `fn` function.
3372  */
3373
3374 /**
3375  * @ngdoc method
3376  * @name $injector#has
3377  *
3378  * @description
3379  * Allows the user to query if the particular service exists.
3380  *
3381  * @param {string} Name of the service to query.
3382  * @returns {boolean} returns true if injector has given service.
3383  */
3384
3385 /**
3386  * @ngdoc method
3387  * @name $injector#instantiate
3388  * @description
3389  * Create a new instance of JS type. The method takes a constructor function, invokes the new
3390  * operator, and supplies all of the arguments to the constructor function as specified by the
3391  * constructor annotation.
3392  *
3393  * @param {Function} Type Annotated constructor function.
3394  * @param {Object=} locals Optional object. If preset then any argument names are read from this
3395  * object first, before the `$injector` is consulted.
3396  * @returns {Object} new instance of `Type`.
3397  */
3398
3399 /**
3400  * @ngdoc method
3401  * @name $injector#annotate
3402  *
3403  * @description
3404  * Returns an array of service names which the function is requesting for injection. This API is
3405  * used by the injector to determine which services need to be injected into the function when the
3406  * function is invoked. There are three ways in which the function can be annotated with the needed
3407  * dependencies.
3408  *
3409  * # Argument names
3410  *
3411  * The simplest form is to extract the dependencies from the arguments of the function. This is done
3412  * by converting the function into a string using `toString()` method and extracting the argument
3413  * names.
3414  * ```js
3415  *   // Given
3416  *   function MyController($scope, $route) {
3417  *     // ...
3418  *   }
3419  *
3420  *   // Then
3421  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3422  * ```
3423  *
3424  * This method does not work with code minification / obfuscation. For this reason the following
3425  * annotation strategies are supported.
3426  *
3427  * # The `$inject` property
3428  *
3429  * If a function has an `$inject` property and its value is an array of strings, then the strings
3430  * represent names of services to be injected into the function.
3431  * ```js
3432  *   // Given
3433  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3434  *     // ...
3435  *   }
3436  *   // Define function dependencies
3437  *   MyController['$inject'] = ['$scope', '$route'];
3438  *
3439  *   // Then
3440  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3441  * ```
3442  *
3443  * # The array notation
3444  *
3445  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3446  * is very inconvenient. In these situations using the array notation to specify the dependencies in
3447  * a way that survives minification is a better choice:
3448  *
3449  * ```js
3450  *   // We wish to write this (not minification / obfuscation safe)
3451  *   injector.invoke(function($compile, $rootScope) {
3452  *     // ...
3453  *   });
3454  *
3455  *   // We are forced to write break inlining
3456  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3457  *     // ...
3458  *   };
3459  *   tmpFn.$inject = ['$compile', '$rootScope'];
3460  *   injector.invoke(tmpFn);
3461  *
3462  *   // To better support inline function the inline annotation is supported
3463  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3464  *     // ...
3465  *   }]);
3466  *
3467  *   // Therefore
3468  *   expect(injector.annotate(
3469  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3470  *    ).toEqual(['$compile', '$rootScope']);
3471  * ```
3472  *
3473  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3474  * be retrieved as described above.
3475  *
3476  * @returns {Array.<string>} The names of the services which the function requires.
3477  */
3478
3479
3480
3481
3482 /**
3483  * @ngdoc service
3484  * @name $provide
3485  *
3486  * @description
3487  *
3488  * The {@link auto.$provide $provide} service has a number of methods for registering components
3489  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3490  * {@link angular.Module}.
3491  *
3492  * An Angular **service** is a singleton object created by a **service factory**.  These **service
3493  * factories** are functions which, in turn, are created by a **service provider**.
3494  * The **service providers** are constructor functions. When instantiated they must contain a
3495  * property called `$get`, which holds the **service factory** function.
3496  *
3497  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3498  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3499  * function to get the instance of the **service**.
3500  *
3501  * Often services have no configuration options and there is no need to add methods to the service
3502  * provider.  The provider will be no more than a constructor function with a `$get` property. For
3503  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3504  * services without specifying a provider.
3505  *
3506  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3507  *     {@link auto.$injector $injector}
3508  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3509  *     providers and services.
3510  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3511  *     services, not providers.
3512  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3513  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3514  *     given factory function.
3515  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3516  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3517  *      a new object using the given constructor function.
3518  *
3519  * See the individual methods for more information and examples.
3520  */
3521
3522 /**
3523  * @ngdoc method
3524  * @name $provide#provider
3525  * @description
3526  *
3527  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3528  * are constructor functions, whose instances are responsible for "providing" a factory for a
3529  * service.
3530  *
3531  * Service provider names start with the name of the service they provide followed by `Provider`.
3532  * For example, the {@link ng.$log $log} service has a provider called
3533  * {@link ng.$logProvider $logProvider}.
3534  *
3535  * Service provider objects can have additional methods which allow configuration of the provider
3536  * and its service. Importantly, you can configure what kind of service is created by the `$get`
3537  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3538  * method {@link ng.$logProvider#debugEnabled debugEnabled}
3539  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3540  * console or not.
3541  *
3542  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3543                         'Provider'` key.
3544  * @param {(Object|function())} provider If the provider is:
3545  *
3546  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3547  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3548  *   - `Constructor`: a new instance of the provider will be created using
3549  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3550  *
3551  * @returns {Object} registered provider instance
3552
3553  * @example
3554  *
3555  * The following example shows how to create a simple event tracking service and register it using
3556  * {@link auto.$provide#provider $provide.provider()}.
3557  *
3558  * ```js
3559  *  // Define the eventTracker provider
3560  *  function EventTrackerProvider() {
3561  *    var trackingUrl = '/track';
3562  *
3563  *    // A provider method for configuring where the tracked events should been saved
3564  *    this.setTrackingUrl = function(url) {
3565  *      trackingUrl = url;
3566  *    };
3567  *
3568  *    // The service factory function
3569  *    this.$get = ['$http', function($http) {
3570  *      var trackedEvents = {};
3571  *      return {
3572  *        // Call this to track an event
3573  *        event: function(event) {
3574  *          var count = trackedEvents[event] || 0;
3575  *          count += 1;
3576  *          trackedEvents[event] = count;
3577  *          return count;
3578  *        },
3579  *        // Call this to save the tracked events to the trackingUrl
3580  *        save: function() {
3581  *          $http.post(trackingUrl, trackedEvents);
3582  *        }
3583  *      };
3584  *    }];
3585  *  }
3586  *
3587  *  describe('eventTracker', function() {
3588  *    var postSpy;
3589  *
3590  *    beforeEach(module(function($provide) {
3591  *      // Register the eventTracker provider
3592  *      $provide.provider('eventTracker', EventTrackerProvider);
3593  *    }));
3594  *
3595  *    beforeEach(module(function(eventTrackerProvider) {
3596  *      // Configure eventTracker provider
3597  *      eventTrackerProvider.setTrackingUrl('/custom-track');
3598  *    }));
3599  *
3600  *    it('tracks events', inject(function(eventTracker) {
3601  *      expect(eventTracker.event('login')).toEqual(1);
3602  *      expect(eventTracker.event('login')).toEqual(2);
3603  *    }));
3604  *
3605  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3606  *      postSpy = spyOn($http, 'post');
3607  *      eventTracker.event('login');
3608  *      eventTracker.save();
3609  *      expect(postSpy).toHaveBeenCalled();
3610  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3611  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3612  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3613  *    }));
3614  *  });
3615  * ```
3616  */
3617
3618 /**
3619  * @ngdoc method
3620  * @name $provide#factory
3621  * @description
3622  *
3623  * Register a **service factory**, which will be called to return the service instance.
3624  * This is short for registering a service where its provider consists of only a `$get` property,
3625  * which is the given service factory function.
3626  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3627  * configure your service in a provider.
3628  *
3629  * @param {string} name The name of the instance.
3630  * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3631  *                            for `$provide.provider(name, {$get: $getFn})`.
3632  * @returns {Object} registered provider instance
3633  *
3634  * @example
3635  * Here is an example of registering a service
3636  * ```js
3637  *   $provide.factory('ping', ['$http', function($http) {
3638  *     return function ping() {
3639  *       return $http.send('/ping');
3640  *     };
3641  *   }]);
3642  * ```
3643  * You would then inject and use this service like this:
3644  * ```js
3645  *   someModule.controller('Ctrl', ['ping', function(ping) {
3646  *     ping();
3647  *   }]);
3648  * ```
3649  */
3650
3651
3652 /**
3653  * @ngdoc method
3654  * @name $provide#service
3655  * @description
3656  *
3657  * Register a **service constructor**, which will be invoked with `new` to create the service
3658  * instance.
3659  * This is short for registering a service where its provider's `$get` property is the service
3660  * constructor function that will be used to instantiate the service instance.
3661  *
3662  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3663  * as a type/class.
3664  *
3665  * @param {string} name The name of the instance.
3666  * @param {Function} constructor A class (constructor function) that will be instantiated.
3667  * @returns {Object} registered provider instance
3668  *
3669  * @example
3670  * Here is an example of registering a service using
3671  * {@link auto.$provide#service $provide.service(class)}.
3672  * ```js
3673  *   var Ping = function($http) {
3674  *     this.$http = $http;
3675  *   };
3676  *
3677  *   Ping.$inject = ['$http'];
3678  *
3679  *   Ping.prototype.send = function() {
3680  *     return this.$http.get('/ping');
3681  *   };
3682  *   $provide.service('ping', Ping);
3683  * ```
3684  * You would then inject and use this service like this:
3685  * ```js
3686  *   someModule.controller('Ctrl', ['ping', function(ping) {
3687  *     ping.send();
3688  *   }]);
3689  * ```
3690  */
3691
3692
3693 /**
3694  * @ngdoc method
3695  * @name $provide#value
3696  * @description
3697  *
3698  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3699  * number, an array, an object or a function.  This is short for registering a service where its
3700  * provider's `$get` property is a factory function that takes no arguments and returns the **value
3701  * service**.
3702  *
3703  * Value services are similar to constant services, except that they cannot be injected into a
3704  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3705  * an Angular
3706  * {@link auto.$provide#decorator decorator}.
3707  *
3708  * @param {string} name The name of the instance.
3709  * @param {*} value The value.
3710  * @returns {Object} registered provider instance
3711  *
3712  * @example
3713  * Here are some examples of creating value services.
3714  * ```js
3715  *   $provide.value('ADMIN_USER', 'admin');
3716  *
3717  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3718  *
3719  *   $provide.value('halfOf', function(value) {
3720  *     return value / 2;
3721  *   });
3722  * ```
3723  */
3724
3725
3726 /**
3727  * @ngdoc method
3728  * @name $provide#constant
3729  * @description
3730  *
3731  * Register a **constant service**, such as a string, a number, an array, an object or a function,
3732  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3733  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3734  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3735  *
3736  * @param {string} name The name of the constant.
3737  * @param {*} value The constant value.
3738  * @returns {Object} registered instance
3739  *
3740  * @example
3741  * Here a some examples of creating constants:
3742  * ```js
3743  *   $provide.constant('SHARD_HEIGHT', 306);
3744  *
3745  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3746  *
3747  *   $provide.constant('double', function(value) {
3748  *     return value * 2;
3749  *   });
3750  * ```
3751  */
3752
3753
3754 /**
3755  * @ngdoc method
3756  * @name $provide#decorator
3757  * @description
3758  *
3759  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3760  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3761  * service. The object returned by the decorator may be the original service, or a new service
3762  * object which replaces or wraps and delegates to the original service.
3763  *
3764  * @param {string} name The name of the service to decorate.
3765  * @param {function()} decorator This function will be invoked when the service needs to be
3766  *    instantiated and should return the decorated service instance. The function is called using
3767  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3768  *    Local injection arguments:
3769  *
3770  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3771  *      decorated or delegated to.
3772  *
3773  * @example
3774  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3775  * calls to {@link ng.$log#error $log.warn()}.
3776  * ```js
3777  *   $provide.decorator('$log', ['$delegate', function($delegate) {
3778  *     $delegate.warn = $delegate.error;
3779  *     return $delegate;
3780  *   }]);
3781  * ```
3782  */
3783
3784
3785 function createInjector(modulesToLoad) {
3786   var INSTANTIATING = {},
3787       providerSuffix = 'Provider',
3788       path = [],
3789       loadedModules = new HashMap([], true),
3790       providerCache = {
3791         $provide: {
3792             provider: supportObject(provider),
3793             factory: supportObject(factory),
3794             service: supportObject(service),
3795             value: supportObject(value),
3796             constant: supportObject(constant),
3797             decorator: decorator
3798           }
3799       },
3800       providerInjector = (providerCache.$injector =
3801           createInternalInjector(providerCache, function() {
3802             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3803           })),
3804       instanceCache = {},
3805       instanceInjector = (instanceCache.$injector =
3806           createInternalInjector(instanceCache, function(servicename) {
3807             var provider = providerInjector.get(servicename + providerSuffix);
3808             return instanceInjector.invoke(provider.$get, provider);
3809           }));
3810
3811
3812   forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3813
3814   return instanceInjector;
3815
3816   ////////////////////////////////////
3817   // $provider
3818   ////////////////////////////////////
3819
3820   function supportObject(delegate) {
3821     return function(key, value) {
3822       if (isObject(key)) {
3823         forEach(key, reverseParams(delegate));
3824       } else {
3825         return delegate(key, value);
3826       }
3827     };
3828   }
3829
3830   function provider(name, provider_) {
3831     assertNotHasOwnProperty(name, 'service');
3832     if (isFunction(provider_) || isArray(provider_)) {
3833       provider_ = providerInjector.instantiate(provider_);
3834     }
3835     if (!provider_.$get) {
3836       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3837     }
3838     return providerCache[name + providerSuffix] = provider_;
3839   }
3840
3841   function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3842
3843   function service(name, constructor) {
3844     return factory(name, ['$injector', function($injector) {
3845       return $injector.instantiate(constructor);
3846     }]);
3847   }
3848
3849   function value(name, val) { return factory(name, valueFn(val)); }
3850
3851   function constant(name, value) {
3852     assertNotHasOwnProperty(name, 'constant');
3853     providerCache[name] = value;
3854     instanceCache[name] = value;
3855   }
3856
3857   function decorator(serviceName, decorFn) {
3858     var origProvider = providerInjector.get(serviceName + providerSuffix),
3859         orig$get = origProvider.$get;
3860
3861     origProvider.$get = function() {
3862       var origInstance = instanceInjector.invoke(orig$get, origProvider);
3863       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3864     };
3865   }
3866
3867   ////////////////////////////////////
3868   // Module Loading
3869   ////////////////////////////////////
3870   function loadModules(modulesToLoad){
3871     var runBlocks = [], moduleFn, invokeQueue, i, ii;
3872     forEach(modulesToLoad, function(module) {
3873       if (loadedModules.get(module)) return;
3874       loadedModules.put(module, true);
3875
3876       try {
3877         if (isString(module)) {
3878           moduleFn = angularModule(module);
3879           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3880
3881           for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3882             var invokeArgs = invokeQueue[i],
3883                 provider = providerInjector.get(invokeArgs[0]);
3884
3885             provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3886           }
3887         } else if (isFunction(module)) {
3888             runBlocks.push(providerInjector.invoke(module));
3889         } else if (isArray(module)) {
3890             runBlocks.push(providerInjector.invoke(module));
3891         } else {
3892           assertArgFn(module, 'module');
3893         }
3894       } catch (e) {
3895         if (isArray(module)) {
3896           module = module[module.length - 1];
3897         }
3898         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3899           // Safari & FF's stack traces don't contain error.message content
3900           // unlike those of Chrome and IE
3901           // So if stack doesn't contain message, we create a new string that contains both.
3902           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3903           /* jshint -W022 */
3904           e = e.message + '\n' + e.stack;
3905         }
3906         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3907                   module, e.stack || e.message || e);
3908       }
3909     });
3910     return runBlocks;
3911   }
3912
3913   ////////////////////////////////////
3914   // internal Injector
3915   ////////////////////////////////////
3916
3917   function createInternalInjector(cache, factory) {
3918
3919     function getService(serviceName) {
3920       if (cache.hasOwnProperty(serviceName)) {
3921         if (cache[serviceName] === INSTANTIATING) {
3922           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
3923                     serviceName + ' <- ' + path.join(' <- '));
3924         }
3925         return cache[serviceName];
3926       } else {
3927         try {
3928           path.unshift(serviceName);
3929           cache[serviceName] = INSTANTIATING;
3930           return cache[serviceName] = factory(serviceName);
3931         } catch (err) {
3932           if (cache[serviceName] === INSTANTIATING) {
3933             delete cache[serviceName];
3934           }
3935           throw err;
3936         } finally {
3937           path.shift();
3938         }
3939       }
3940     }
3941
3942     function invoke(fn, self, locals){
3943       var args = [],
3944           $inject = annotate(fn),
3945           length, i,
3946           key;
3947
3948       for(i = 0, length = $inject.length; i < length; i++) {
3949         key = $inject[i];
3950         if (typeof key !== 'string') {
3951           throw $injectorMinErr('itkn',
3952                   'Incorrect injection token! Expected service name as string, got {0}', key);
3953         }
3954         args.push(
3955           locals && locals.hasOwnProperty(key)
3956           ? locals[key]
3957           : getService(key)
3958         );
3959       }
3960       if (isArray(fn)) {
3961         fn = fn[length];
3962       }
3963
3964       // http://jsperf.com/angularjs-invoke-apply-vs-switch
3965       // #5388
3966       return fn.apply(self, args);
3967     }
3968
3969     function instantiate(Type, locals) {
3970       var Constructor = function() {},
3971           instance, returnedValue;
3972
3973       // Check if Type is annotated and use just the given function at n-1 as parameter
3974       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3975       Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3976       instance = new Constructor();
3977       returnedValue = invoke(Type, instance, locals);
3978
3979       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3980     }
3981
3982     return {
3983       invoke: invoke,
3984       instantiate: instantiate,
3985       get: getService,
3986       annotate: annotate,
3987       has: function(name) {
3988         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3989       }
3990     };
3991   }
3992 }
3993
3994 /**
3995  * @ngdoc service
3996  * @name $anchorScroll
3997  * @kind function
3998  * @requires $window
3999  * @requires $location
4000  * @requires $rootScope
4001  *
4002  * @description
4003  * When called, it checks current value of `$location.hash()` and scrolls to the related element,
4004  * according to rules specified in
4005  * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4006  *
4007  * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
4008  * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
4009  *
4010  * @example
4011    <example>
4012      <file name="index.html">
4013        <div id="scrollArea" ng-controller="ScrollCtrl">
4014          <a ng-click="gotoBottom()">Go to bottom</a>
4015          <a id="bottom"></a> You're at the bottom!
4016        </div>
4017      </file>
4018      <file name="script.js">
4019        function ScrollCtrl($scope, $location, $anchorScroll) {
4020          $scope.gotoBottom = function (){
4021            // set the location.hash to the id of
4022            // the element you wish to scroll to.
4023            $location.hash('bottom');
4024
4025            // call $anchorScroll()
4026            $anchorScroll();
4027          };
4028        }
4029      </file>
4030      <file name="style.css">
4031        #scrollArea {
4032          height: 350px;
4033          overflow: auto;
4034        }
4035
4036        #bottom {
4037          display: block;
4038          margin-top: 2000px;
4039        }
4040      </file>
4041    </example>
4042  */
4043 function $AnchorScrollProvider() {
4044
4045   var autoScrollingEnabled = true;
4046
4047   this.disableAutoScrolling = function() {
4048     autoScrollingEnabled = false;
4049   };
4050
4051   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4052     var document = $window.document;
4053
4054     // helper function to get first anchor from a NodeList
4055     // can't use filter.filter, as it accepts only instances of Array
4056     // and IE can't convert NodeList to an array using [].slice
4057     // TODO(vojta): use filter if we change it to accept lists as well
4058     function getFirstAnchor(list) {
4059       var result = null;
4060       forEach(list, function(element) {
4061         if (!result && lowercase(element.nodeName) === 'a') result = element;
4062       });
4063       return result;
4064     }
4065
4066     function scroll() {
4067       var hash = $location.hash(), elm;
4068
4069       // empty hash, scroll to the top of the page
4070       if (!hash) $window.scrollTo(0, 0);
4071
4072       // element with given id
4073       else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4074
4075       // first anchor with given name :-D
4076       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4077
4078       // no element and hash == 'top', scroll to the top of the page
4079       else if (hash === 'top') $window.scrollTo(0, 0);
4080     }
4081
4082     // does not scroll when user clicks on anchor link that is currently on
4083     // (no url change, no $location.hash() change), browser native does scroll
4084     if (autoScrollingEnabled) {
4085       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4086         function autoScrollWatchAction() {
4087           $rootScope.$evalAsync(scroll);
4088         });
4089     }
4090
4091     return scroll;
4092   }];
4093 }
4094
4095 var $animateMinErr = minErr('$animate');
4096
4097 /**
4098  * @ngdoc provider
4099  * @name $animateProvider
4100  *
4101  * @description
4102  * Default implementation of $animate that doesn't perform any animations, instead just
4103  * synchronously performs DOM
4104  * updates and calls done() callbacks.
4105  *
4106  * In order to enable animations the ngAnimate module has to be loaded.
4107  *
4108  * To see the functional implementation check out src/ngAnimate/animate.js
4109  */
4110 var $AnimateProvider = ['$provide', function($provide) {
4111
4112
4113   this.$$selectors = {};
4114
4115
4116   /**
4117    * @ngdoc method
4118    * @name $animateProvider#register
4119    *
4120    * @description
4121    * Registers a new injectable animation factory function. The factory function produces the
4122    * animation object which contains callback functions for each event that is expected to be
4123    * animated.
4124    *
4125    *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4126    *   must be called once the element animation is complete. If a function is returned then the
4127    *   animation service will use this function to cancel the animation whenever a cancel event is
4128    *   triggered.
4129    *
4130    *
4131    * ```js
4132    *   return {
4133      *     eventFn : function(element, done) {
4134      *       //code to run the animation
4135      *       //once complete, then run done()
4136      *       return function cancellationFunction() {
4137      *         //code to cancel the animation
4138      *       }
4139      *     }
4140      *   }
4141    * ```
4142    *
4143    * @param {string} name The name of the animation.
4144    * @param {Function} factory The factory function that will be executed to return the animation
4145    *                           object.
4146    */
4147   this.register = function(name, factory) {
4148     var key = name + '-animation';
4149     if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4150         "Expecting class selector starting with '.' got '{0}'.", name);
4151     this.$$selectors[name.substr(1)] = key;
4152     $provide.factory(key, factory);
4153   };
4154
4155   /**
4156    * @ngdoc method
4157    * @name $animateProvider#classNameFilter
4158    *
4159    * @description
4160    * Sets and/or returns the CSS class regular expression that is checked when performing
4161    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4162    * therefore enable $animate to attempt to perform an animation on any element.
4163    * When setting the classNameFilter value, animations will only be performed on elements
4164    * that successfully match the filter expression. This in turn can boost performance
4165    * for low-powered devices as well as applications containing a lot of structural operations.
4166    * @param {RegExp=} expression The className expression which will be checked against all animations
4167    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4168    */
4169   this.classNameFilter = function(expression) {
4170     if(arguments.length === 1) {
4171       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4172     }
4173     return this.$$classNameFilter;
4174   };
4175
4176   this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
4177
4178     function async(fn) {
4179       fn && $$asyncCallback(fn);
4180     }
4181
4182     /**
4183      *
4184      * @ngdoc service
4185      * @name $animate
4186      * @description The $animate service provides rudimentary DOM manipulation functions to
4187      * insert, remove and move elements within the DOM, as well as adding and removing classes.
4188      * This service is the core service used by the ngAnimate $animator service which provides
4189      * high-level animation hooks for CSS and JavaScript.
4190      *
4191      * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4192      * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4193      * manipulation operations.
4194      *
4195      * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4196      * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4197      * page}.
4198      */
4199     return {
4200
4201       /**
4202        *
4203        * @ngdoc method
4204        * @name $animate#enter
4205        * @kind function
4206        * @description Inserts the element into the DOM either after the `after` element or within
4207        *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4208        * @param {DOMElement} element the element which will be inserted into the DOM
4209        * @param {DOMElement} parent the parent element which will append the element as
4210        *   a child (if the after element is not present)
4211        * @param {DOMElement} after the sibling element which will append the element
4212        *   after itself
4213        * @param {Function=} done callback function that will be called after the element has been
4214        *   inserted into the DOM
4215        */
4216       enter : function(element, parent, after, done) {
4217         if (after) {
4218           after.after(element);
4219         } else {
4220           if (!parent || !parent[0]) {
4221             parent = after.parent();
4222           }
4223           parent.append(element);
4224         }
4225         async(done);
4226       },
4227
4228       /**
4229        *
4230        * @ngdoc method
4231        * @name $animate#leave
4232        * @kind function
4233        * @description Removes the element from the DOM. Once complete, the done() callback will be
4234        *   fired (if provided).
4235        * @param {DOMElement} element the element which will be removed from the DOM
4236        * @param {Function=} done callback function that will be called after the element has been
4237        *   removed from the DOM
4238        */
4239       leave : function(element, done) {
4240         element.remove();
4241         async(done);
4242       },
4243
4244       /**
4245        *
4246        * @ngdoc method
4247        * @name $animate#move
4248        * @kind function
4249        * @description Moves the position of the provided element within the DOM to be placed
4250        * either after the `after` element or inside of the `parent` element. Once complete, the
4251        * done() callback will be fired (if provided).
4252        *
4253        * @param {DOMElement} element the element which will be moved around within the
4254        *   DOM
4255        * @param {DOMElement} parent the parent element where the element will be
4256        *   inserted into (if the after element is not present)
4257        * @param {DOMElement} after the sibling element where the element will be
4258        *   positioned next to
4259        * @param {Function=} done the callback function (if provided) that will be fired after the
4260        *   element has been moved to its new position
4261        */
4262       move : function(element, parent, after, done) {
4263         // Do not remove element before insert. Removing will cause data associated with the
4264         // element to be dropped. Insert will implicitly do the remove.
4265         this.enter(element, parent, after, done);
4266       },
4267
4268       /**
4269        *
4270        * @ngdoc method
4271        * @name $animate#addClass
4272        * @kind function
4273        * @description Adds the provided className CSS class value to the provided element. Once
4274        * complete, the done() callback will be fired (if provided).
4275        * @param {DOMElement} element the element which will have the className value
4276        *   added to it
4277        * @param {string} className the CSS class which will be added to the element
4278        * @param {Function=} done the callback function (if provided) that will be fired after the
4279        *   className value has been added to the element
4280        */
4281       addClass : function(element, className, done) {
4282         className = isString(className) ?
4283                       className :
4284                       isArray(className) ? className.join(' ') : '';
4285         forEach(element, function (element) {
4286           jqLiteAddClass(element, className);
4287         });
4288         async(done);
4289       },
4290
4291       /**
4292        *
4293        * @ngdoc method
4294        * @name $animate#removeClass
4295        * @kind function
4296        * @description Removes the provided className CSS class value from the provided element.
4297        * Once complete, the done() callback will be fired (if provided).
4298        * @param {DOMElement} element the element which will have the className value
4299        *   removed from it
4300        * @param {string} className the CSS class which will be removed from the element
4301        * @param {Function=} done the callback function (if provided) that will be fired after the
4302        *   className value has been removed from the element
4303        */
4304       removeClass : function(element, className, done) {
4305         className = isString(className) ?
4306                       className :
4307                       isArray(className) ? className.join(' ') : '';
4308         forEach(element, function (element) {
4309           jqLiteRemoveClass(element, className);
4310         });
4311         async(done);
4312       },
4313
4314       /**
4315        *
4316        * @ngdoc method
4317        * @name $animate#setClass
4318        * @kind function
4319        * @description Adds and/or removes the given CSS classes to and from the element.
4320        * Once complete, the done() callback will be fired (if provided).
4321        * @param {DOMElement} element the element which will have its CSS classes changed
4322        *   removed from it
4323        * @param {string} add the CSS classes which will be added to the element
4324        * @param {string} remove the CSS class which will be removed from the element
4325        * @param {Function=} done the callback function (if provided) that will be fired after the
4326        *   CSS classes have been set on the element
4327        */
4328       setClass : function(element, add, remove, done) {
4329         forEach(element, function (element) {
4330           jqLiteAddClass(element, add);
4331           jqLiteRemoveClass(element, remove);
4332         });
4333         async(done);
4334       },
4335
4336       enabled : noop
4337     };
4338   }];
4339 }];
4340
4341 function $$AsyncCallbackProvider(){
4342   this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4343     return $$rAF.supported
4344       ? function(fn) { return $$rAF(fn); }
4345       : function(fn) {
4346         return $timeout(fn, 0, false);
4347       };
4348   }];
4349 }
4350
4351 /**
4352  * ! This is a private undocumented service !
4353  *
4354  * @name $browser
4355  * @requires $log
4356  * @description
4357  * This object has two goals:
4358  *
4359  * - hide all the global state in the browser caused by the window object
4360  * - abstract away all the browser specific features and inconsistencies
4361  *
4362  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4363  * service, which can be used for convenient testing of the application without the interaction with
4364  * the real browser apis.
4365  */
4366 /**
4367  * @param {object} window The global window object.
4368  * @param {object} document jQuery wrapped document.
4369  * @param {function()} XHR XMLHttpRequest constructor.
4370  * @param {object} $log console.log or an object with the same interface.
4371  * @param {object} $sniffer $sniffer service
4372  */
4373 function Browser(window, document, $log, $sniffer) {
4374   var self = this,
4375       rawDocument = document[0],
4376       location = window.location,
4377       history = window.history,
4378       setTimeout = window.setTimeout,
4379       clearTimeout = window.clearTimeout,
4380       pendingDeferIds = {};
4381
4382   self.isMock = false;
4383
4384   var outstandingRequestCount = 0;
4385   var outstandingRequestCallbacks = [];
4386
4387   // TODO(vojta): remove this temporary api
4388   self.$$completeOutstandingRequest = completeOutstandingRequest;
4389   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4390
4391   /**
4392    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4393    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4394    */
4395   function completeOutstandingRequest(fn) {
4396     try {
4397       fn.apply(null, sliceArgs(arguments, 1));
4398     } finally {
4399       outstandingRequestCount--;
4400       if (outstandingRequestCount === 0) {
4401         while(outstandingRequestCallbacks.length) {
4402           try {
4403             outstandingRequestCallbacks.pop()();
4404           } catch (e) {
4405             $log.error(e);
4406           }
4407         }
4408       }
4409     }
4410   }
4411
4412   /**
4413    * @private
4414    * Note: this method is used only by scenario runner
4415    * TODO(vojta): prefix this method with $$ ?
4416    * @param {function()} callback Function that will be called when no outstanding request
4417    */
4418   self.notifyWhenNoOutstandingRequests = function(callback) {
4419     // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4420     // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4421     // regular poller would result in flaky tests.
4422     forEach(pollFns, function(pollFn){ pollFn(); });
4423
4424     if (outstandingRequestCount === 0) {
4425       callback();
4426     } else {
4427       outstandingRequestCallbacks.push(callback);
4428     }
4429   };
4430
4431   //////////////////////////////////////////////////////////////
4432   // Poll Watcher API
4433   //////////////////////////////////////////////////////////////
4434   var pollFns = [],
4435       pollTimeout;
4436
4437   /**
4438    * @name $browser#addPollFn
4439    *
4440    * @param {function()} fn Poll function to add
4441    *
4442    * @description
4443    * Adds a function to the list of functions that poller periodically executes,
4444    * and starts polling if not started yet.
4445    *
4446    * @returns {function()} the added function
4447    */
4448   self.addPollFn = function(fn) {
4449     if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4450     pollFns.push(fn);
4451     return fn;
4452   };
4453
4454   /**
4455    * @param {number} interval How often should browser call poll functions (ms)
4456    * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4457    *
4458    * @description
4459    * Configures the poller to run in the specified intervals, using the specified
4460    * setTimeout fn and kicks it off.
4461    */
4462   function startPoller(interval, setTimeout) {
4463     (function check() {
4464       forEach(pollFns, function(pollFn){ pollFn(); });
4465       pollTimeout = setTimeout(check, interval);
4466     })();
4467   }
4468
4469   //////////////////////////////////////////////////////////////
4470   // URL API
4471   //////////////////////////////////////////////////////////////
4472
4473   var lastBrowserUrl = location.href,
4474       baseElement = document.find('base'),
4475       newLocation = null;
4476
4477   /**
4478    * @name $browser#url
4479    *
4480    * @description
4481    * GETTER:
4482    * Without any argument, this method just returns current value of location.href.
4483    *
4484    * SETTER:
4485    * With at least one argument, this method sets url to new value.
4486    * If html5 history api supported, pushState/replaceState is used, otherwise
4487    * location.href/location.replace is used.
4488    * Returns its own instance to allow chaining
4489    *
4490    * NOTE: this api is intended for use only by the $location service. Please use the
4491    * {@link ng.$location $location service} to change url.
4492    *
4493    * @param {string} url New url (when used as setter)
4494    * @param {boolean=} replace Should new url replace current history record ?
4495    */
4496   self.url = function(url, replace) {
4497     // Android Browser BFCache causes location, history reference to become stale.
4498     if (location !== window.location) location = window.location;
4499     if (history !== window.history) history = window.history;
4500
4501     // setter
4502     if (url) {
4503       if (lastBrowserUrl == url) return;
4504       lastBrowserUrl = url;
4505       if ($sniffer.history) {
4506         if (replace) history.replaceState(null, '', url);
4507         else {
4508           history.pushState(null, '', url);
4509           // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4510           baseElement.attr('href', baseElement.attr('href'));
4511         }
4512       } else {
4513         newLocation = url;
4514         if (replace) {
4515           location.replace(url);
4516         } else {
4517           location.href = url;
4518         }
4519       }
4520       return self;
4521     // getter
4522     } else {
4523       // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4524       //   methods not updating location.href synchronously.
4525       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4526       return newLocation || location.href.replace(/%27/g,"'");
4527     }
4528   };
4529
4530   var urlChangeListeners = [],
4531       urlChangeInit = false;
4532
4533   function fireUrlChange() {
4534     newLocation = null;
4535     if (lastBrowserUrl == self.url()) return;
4536
4537     lastBrowserUrl = self.url();
4538     forEach(urlChangeListeners, function(listener) {
4539       listener(self.url());
4540     });
4541   }
4542
4543   /**
4544    * @name $browser#onUrlChange
4545    *
4546    * @description
4547    * Register callback function that will be called, when url changes.
4548    *
4549    * It's only called when the url is changed from outside of angular:
4550    * - user types different url into address bar
4551    * - user clicks on history (forward/back) button
4552    * - user clicks on a link
4553    *
4554    * It's not called when url is changed by $browser.url() method
4555    *
4556    * The listener gets called with new url as parameter.
4557    *
4558    * NOTE: this api is intended for use only by the $location service. Please use the
4559    * {@link ng.$location $location service} to monitor url changes in angular apps.
4560    *
4561    * @param {function(string)} listener Listener function to be called when url changes.
4562    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4563    */
4564   self.onUrlChange = function(callback) {
4565     // TODO(vojta): refactor to use node's syntax for events
4566     if (!urlChangeInit) {
4567       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4568       // don't fire popstate when user change the address bar and don't fire hashchange when url
4569       // changed by push/replaceState
4570
4571       // html5 history api - popstate event
4572       if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4573       // hashchange event
4574       if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4575       // polling
4576       else self.addPollFn(fireUrlChange);
4577
4578       urlChangeInit = true;
4579     }
4580
4581     urlChangeListeners.push(callback);
4582     return callback;
4583   };
4584
4585   /**
4586    * Checks whether the url has changed outside of Angular.
4587    * Needs to be exported to be able to check for changes that have been done in sync,
4588    * as hashchange/popstate events fire in async.
4589    */
4590   self.$$checkUrlChange = fireUrlChange;
4591
4592   //////////////////////////////////////////////////////////////
4593   // Misc API
4594   //////////////////////////////////////////////////////////////
4595
4596   /**
4597    * @name $browser#baseHref
4598    *
4599    * @description
4600    * Returns current <base href>
4601    * (always relative - without domain)
4602    *
4603    * @returns {string} The current base href
4604    */
4605   self.baseHref = function() {
4606     var href = baseElement.attr('href');
4607     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4608   };
4609
4610   //////////////////////////////////////////////////////////////
4611   // Cookies API
4612   //////////////////////////////////////////////////////////////
4613   var lastCookies = {};
4614   var lastCookieString = '';
4615   var cookiePath = self.baseHref();
4616
4617   /**
4618    * @name $browser#cookies
4619    *
4620    * @param {string=} name Cookie name
4621    * @param {string=} value Cookie value
4622    *
4623    * @description
4624    * The cookies method provides a 'private' low level access to browser cookies.
4625    * It is not meant to be used directly, use the $cookie service instead.
4626    *
4627    * The return values vary depending on the arguments that the method was called with as follows:
4628    *
4629    * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4630    *   it
4631    * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4632    * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4633    *   way)
4634    *
4635    * @returns {Object} Hash of all cookies (if called without any parameter)
4636    */
4637   self.cookies = function(name, value) {
4638     /* global escape: false, unescape: false */
4639     var cookieLength, cookieArray, cookie, i, index;
4640
4641     if (name) {
4642       if (value === undefined) {
4643         rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
4644                                 ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4645       } else {
4646         if (isString(value)) {
4647           cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4648                                 ';path=' + cookiePath).length + 1;
4649
4650           // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4651           // - 300 cookies
4652           // - 20 cookies per unique domain
4653           // - 4096 bytes per cookie
4654           if (cookieLength > 4096) {
4655             $log.warn("Cookie '"+ name +
4656               "' possibly not set or overflowed because it was too large ("+
4657               cookieLength + " > 4096 bytes)!");
4658           }
4659         }
4660       }
4661     } else {
4662       if (rawDocument.cookie !== lastCookieString) {
4663         lastCookieString = rawDocument.cookie;
4664         cookieArray = lastCookieString.split("; ");
4665         lastCookies = {};
4666
4667         for (i = 0; i < cookieArray.length; i++) {
4668           cookie = cookieArray[i];
4669           index = cookie.indexOf('=');
4670           if (index > 0) { //ignore nameless cookies
4671             name = unescape(cookie.substring(0, index));
4672             // the first value that is seen for a cookie is the most
4673             // specific one.  values for the same cookie name that
4674             // follow are for less specific paths.
4675             if (lastCookies[name] === undefined) {
4676               lastCookies[name] = unescape(cookie.substring(index + 1));
4677             }
4678           }
4679         }
4680       }
4681       return lastCookies;
4682     }
4683   };
4684
4685
4686   /**
4687    * @name $browser#defer
4688    * @param {function()} fn A function, who's execution should be deferred.
4689    * @param {number=} [delay=0] of milliseconds to defer the function execution.
4690    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4691    *
4692    * @description
4693    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4694    *
4695    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4696    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4697    * via `$browser.defer.flush()`.
4698    *
4699    */
4700   self.defer = function(fn, delay) {
4701     var timeoutId;
4702     outstandingRequestCount++;
4703     timeoutId = setTimeout(function() {
4704       delete pendingDeferIds[timeoutId];
4705       completeOutstandingRequest(fn);
4706     }, delay || 0);
4707     pendingDeferIds[timeoutId] = true;
4708     return timeoutId;
4709   };
4710
4711
4712   /**
4713    * @name $browser#defer.cancel
4714    *
4715    * @description
4716    * Cancels a deferred task identified with `deferId`.
4717    *
4718    * @param {*} deferId Token returned by the `$browser.defer` function.
4719    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4720    *                    canceled.
4721    */
4722   self.defer.cancel = function(deferId) {
4723     if (pendingDeferIds[deferId]) {
4724       delete pendingDeferIds[deferId];
4725       clearTimeout(deferId);
4726       completeOutstandingRequest(noop);
4727       return true;
4728     }
4729     return false;
4730   };
4731
4732 }
4733
4734 function $BrowserProvider(){
4735   this.$get = ['$window', '$log', '$sniffer', '$document',
4736       function( $window,   $log,   $sniffer,   $document){
4737         return new Browser($window, $document, $log, $sniffer);
4738       }];
4739 }
4740
4741 /**
4742  * @ngdoc service
4743  * @name $cacheFactory
4744  *
4745  * @description
4746  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4747  * them.
4748  *
4749  * ```js
4750  *
4751  *  var cache = $cacheFactory('cacheId');
4752  *  expect($cacheFactory.get('cacheId')).toBe(cache);
4753  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4754  *
4755  *  cache.put("key", "value");
4756  *  cache.put("another key", "another value");
4757  *
4758  *  // We've specified no options on creation
4759  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4760  *
4761  * ```
4762  *
4763  *
4764  * @param {string} cacheId Name or id of the newly created cache.
4765  * @param {object=} options Options object that specifies the cache behavior. Properties:
4766  *
4767  *   - `{number=}` `capacity` — turns the cache into LRU cache.
4768  *
4769  * @returns {object} Newly created cache object with the following set of methods:
4770  *
4771  * - `{object}` `info()` — Returns id, size, and options of cache.
4772  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4773  *   it.
4774  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4775  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4776  * - `{void}` `removeAll()` — Removes all cached values.
4777  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4778  *
4779  * @example
4780    <example module="cacheExampleApp">
4781      <file name="index.html">
4782        <div ng-controller="CacheController">
4783          <input ng-model="newCacheKey" placeholder="Key">
4784          <input ng-model="newCacheValue" placeholder="Value">
4785          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4786
4787          <p ng-if="keys.length">Cached Values</p>
4788          <div ng-repeat="key in keys">
4789            <span ng-bind="key"></span>
4790            <span>: </span>
4791            <b ng-bind="cache.get(key)"></b>
4792          </div>
4793
4794          <p>Cache Info</p>
4795          <div ng-repeat="(key, value) in cache.info()">
4796            <span ng-bind="key"></span>
4797            <span>: </span>
4798            <b ng-bind="value"></b>
4799          </div>
4800        </div>
4801      </file>
4802      <file name="script.js">
4803        angular.module('cacheExampleApp', []).
4804          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4805            $scope.keys = [];
4806            $scope.cache = $cacheFactory('cacheId');
4807            $scope.put = function(key, value) {
4808              if ($scope.cache.get(key) === undefined) {
4809                $scope.keys.push(key);
4810              }
4811              $scope.cache.put(key, value === undefined ? null : value);
4812            };
4813          }]);
4814      </file>
4815      <file name="style.css">
4816        p {
4817          margin: 10px 0 3px;
4818        }
4819      </file>
4820    </example>
4821  */
4822 function $CacheFactoryProvider() {
4823
4824   this.$get = function() {
4825     var caches = {};
4826
4827     function cacheFactory(cacheId, options) {
4828       if (cacheId in caches) {
4829         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4830       }
4831
4832       var size = 0,
4833           stats = extend({}, options, {id: cacheId}),
4834           data = {},
4835           capacity = (options && options.capacity) || Number.MAX_VALUE,
4836           lruHash = {},
4837           freshEnd = null,
4838           staleEnd = null;
4839
4840       /**
4841        * @ngdoc type
4842        * @name $cacheFactory.Cache
4843        *
4844        * @description
4845        * A cache object used to store and retrieve data, primarily used by
4846        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4847        * templates and other data.
4848        *
4849        * ```js
4850        *  angular.module('superCache')
4851        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4852        *      return $cacheFactory('super-cache');
4853        *    }]);
4854        * ```
4855        *
4856        * Example test:
4857        *
4858        * ```js
4859        *  it('should behave like a cache', inject(function(superCache) {
4860        *    superCache.put('key', 'value');
4861        *    superCache.put('another key', 'another value');
4862        *
4863        *    expect(superCache.info()).toEqual({
4864        *      id: 'super-cache',
4865        *      size: 2
4866        *    });
4867        *
4868        *    superCache.remove('another key');
4869        *    expect(superCache.get('another key')).toBeUndefined();
4870        *
4871        *    superCache.removeAll();
4872        *    expect(superCache.info()).toEqual({
4873        *      id: 'super-cache',
4874        *      size: 0
4875        *    });
4876        *  }));
4877        * ```
4878        */
4879       return caches[cacheId] = {
4880
4881         /**
4882          * @ngdoc method
4883          * @name $cacheFactory.Cache#put
4884          * @kind function
4885          *
4886          * @description
4887          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4888          * retrieved later, and incrementing the size of the cache if the key was not already
4889          * present in the cache. If behaving like an LRU cache, it will also remove stale
4890          * entries from the set.
4891          *
4892          * It will not insert undefined values into the cache.
4893          *
4894          * @param {string} key the key under which the cached data is stored.
4895          * @param {*} value the value to store alongside the key. If it is undefined, the key
4896          *    will not be stored.
4897          * @returns {*} the value stored.
4898          */
4899         put: function(key, value) {
4900           if (capacity < Number.MAX_VALUE) {
4901             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4902
4903             refresh(lruEntry);
4904           }
4905
4906           if (isUndefined(value)) return;
4907           if (!(key in data)) size++;
4908           data[key] = value;
4909
4910           if (size > capacity) {
4911             this.remove(staleEnd.key);
4912           }
4913
4914           return value;
4915         },
4916
4917         /**
4918          * @ngdoc method
4919          * @name $cacheFactory.Cache#get
4920          * @kind function
4921          *
4922          * @description
4923          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4924          *
4925          * @param {string} key the key of the data to be retrieved
4926          * @returns {*} the value stored.
4927          */
4928         get: function(key) {
4929           if (capacity < Number.MAX_VALUE) {
4930             var lruEntry = lruHash[key];
4931
4932             if (!lruEntry) return;
4933
4934             refresh(lruEntry);
4935           }
4936
4937           return data[key];
4938         },
4939
4940
4941         /**
4942          * @ngdoc method
4943          * @name $cacheFactory.Cache#remove
4944          * @kind function
4945          *
4946          * @description
4947          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4948          *
4949          * @param {string} key the key of the entry to be removed
4950          */
4951         remove: function(key) {
4952           if (capacity < Number.MAX_VALUE) {
4953             var lruEntry = lruHash[key];
4954
4955             if (!lruEntry) return;
4956
4957             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4958             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4959             link(lruEntry.n,lruEntry.p);
4960
4961             delete lruHash[key];
4962           }
4963
4964           delete data[key];
4965           size--;
4966         },
4967
4968
4969         /**
4970          * @ngdoc method
4971          * @name $cacheFactory.Cache#removeAll
4972          * @kind function
4973          *
4974          * @description
4975          * Clears the cache object of any entries.
4976          */
4977         removeAll: function() {
4978           data = {};
4979           size = 0;
4980           lruHash = {};
4981           freshEnd = staleEnd = null;
4982         },
4983
4984
4985         /**
4986          * @ngdoc method
4987          * @name $cacheFactory.Cache#destroy
4988          * @kind function
4989          *
4990          * @description
4991          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
4992          * removing it from the {@link $cacheFactory $cacheFactory} set.
4993          */
4994         destroy: function() {
4995           data = null;
4996           stats = null;
4997           lruHash = null;
4998           delete caches[cacheId];
4999         },
5000
5001
5002         /**
5003          * @ngdoc method
5004          * @name $cacheFactory.Cache#info
5005          * @kind function
5006          *
5007          * @description
5008          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5009          *
5010          * @returns {object} an object with the following properties:
5011          *   <ul>
5012          *     <li>**id**: the id of the cache instance</li>
5013          *     <li>**size**: the number of entries kept in the cache instance</li>
5014          *     <li>**...**: any additional properties from the options object when creating the
5015          *       cache.</li>
5016          *   </ul>
5017          */
5018         info: function() {
5019           return extend({}, stats, {size: size});
5020         }
5021       };
5022
5023
5024       /**
5025        * makes the `entry` the freshEnd of the LRU linked list
5026        */
5027       function refresh(entry) {
5028         if (entry != freshEnd) {
5029           if (!staleEnd) {
5030             staleEnd = entry;
5031           } else if (staleEnd == entry) {
5032             staleEnd = entry.n;
5033           }
5034
5035           link(entry.n, entry.p);
5036           link(entry, freshEnd);
5037           freshEnd = entry;
5038           freshEnd.n = null;
5039         }
5040       }
5041
5042
5043       /**
5044        * bidirectionally links two entries of the LRU linked list
5045        */
5046       function link(nextEntry, prevEntry) {
5047         if (nextEntry != prevEntry) {
5048           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5049           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5050         }
5051       }
5052     }
5053
5054
5055   /**
5056    * @ngdoc method
5057    * @name $cacheFactory#info
5058    *
5059    * @description
5060    * Get information about all the caches that have been created
5061    *
5062    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5063    */
5064     cacheFactory.info = function() {
5065       var info = {};
5066       forEach(caches, function(cache, cacheId) {
5067         info[cacheId] = cache.info();
5068       });
5069       return info;
5070     };
5071
5072
5073   /**
5074    * @ngdoc method
5075    * @name $cacheFactory#get
5076    *
5077    * @description
5078    * Get access to a cache object by the `cacheId` used when it was created.
5079    *
5080    * @param {string} cacheId Name or id of a cache to access.
5081    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5082    */
5083     cacheFactory.get = function(cacheId) {
5084       return caches[cacheId];
5085     };
5086
5087
5088     return cacheFactory;
5089   };
5090 }
5091
5092 /**
5093  * @ngdoc service
5094  * @name $templateCache
5095  *
5096  * @description
5097  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5098  * can load templates directly into the cache in a `script` tag, or by consuming the
5099  * `$templateCache` service directly.
5100  *
5101  * Adding via the `script` tag:
5102  *
5103  * ```html
5104  *   <script type="text/ng-template" id="templateId.html">
5105  *     <p>This is the content of the template</p>
5106  *   </script>
5107  * ```
5108  *
5109  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5110  * the document, but it must be below the `ng-app` definition.
5111  *
5112  * Adding via the $templateCache service:
5113  *
5114  * ```js
5115  * var myApp = angular.module('myApp', []);
5116  * myApp.run(function($templateCache) {
5117  *   $templateCache.put('templateId.html', 'This is the content of the template');
5118  * });
5119  * ```
5120  *
5121  * To retrieve the template later, simply use it in your HTML:
5122  * ```html
5123  * <div ng-include=" 'templateId.html' "></div>
5124  * ```
5125  *
5126  * or get it via Javascript:
5127  * ```js
5128  * $templateCache.get('templateId.html')
5129  * ```
5130  *
5131  * See {@link ng.$cacheFactory $cacheFactory}.
5132  *
5133  */
5134 function $TemplateCacheProvider() {
5135   this.$get = ['$cacheFactory', function($cacheFactory) {
5136     return $cacheFactory('templates');
5137   }];
5138 }
5139
5140 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5141  *
5142  * DOM-related variables:
5143  *
5144  * - "node" - DOM Node
5145  * - "element" - DOM Element or Node
5146  * - "$node" or "$element" - jqLite-wrapped node or element
5147  *
5148  *
5149  * Compiler related stuff:
5150  *
5151  * - "linkFn" - linking fn of a single directive
5152  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5153  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5154  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5155  */
5156
5157
5158 /**
5159  * @ngdoc service
5160  * @name $compile
5161  * @kind function
5162  *
5163  * @description
5164  * Compiles an HTML string or DOM into a template and produces a template function, which
5165  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5166  *
5167  * The compilation is a process of walking the DOM tree and matching DOM elements to
5168  * {@link ng.$compileProvider#directive directives}.
5169  *
5170  * <div class="alert alert-warning">
5171  * **Note:** This document is an in-depth reference of all directive options.
5172  * For a gentle introduction to directives with examples of common use cases,
5173  * see the {@link guide/directive directive guide}.
5174  * </div>
5175  *
5176  * ## Comprehensive Directive API
5177  *
5178  * There are many different options for a directive.
5179  *
5180  * The difference resides in the return value of the factory function.
5181  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5182  * or just the `postLink` function (all other properties will have the default values).
5183  *
5184  * <div class="alert alert-success">
5185  * **Best Practice:** It's recommended to use the "directive definition object" form.
5186  * </div>
5187  *
5188  * Here's an example directive declared with a Directive Definition Object:
5189  *
5190  * ```js
5191  *   var myModule = angular.module(...);
5192  *
5193  *   myModule.directive('directiveName', function factory(injectables) {
5194  *     var directiveDefinitionObject = {
5195  *       priority: 0,
5196  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
5197  *       // or
5198  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5199  *       transclude: false,
5200  *       restrict: 'A',
5201  *       scope: false,
5202  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5203  *       controllerAs: 'stringAlias',
5204  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5205  *       compile: function compile(tElement, tAttrs, transclude) {
5206  *         return {
5207  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5208  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5209  *         }
5210  *         // or
5211  *         // return function postLink( ... ) { ... }
5212  *       },
5213  *       // or
5214  *       // link: {
5215  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5216  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5217  *       // }
5218  *       // or
5219  *       // link: function postLink( ... ) { ... }
5220  *     };
5221  *     return directiveDefinitionObject;
5222  *   });
5223  * ```
5224  *
5225  * <div class="alert alert-warning">
5226  * **Note:** Any unspecified options will use the default value. You can see the default values below.
5227  * </div>
5228  *
5229  * Therefore the above can be simplified as:
5230  *
5231  * ```js
5232  *   var myModule = angular.module(...);
5233  *
5234  *   myModule.directive('directiveName', function factory(injectables) {
5235  *     var directiveDefinitionObject = {
5236  *       link: function postLink(scope, iElement, iAttrs) { ... }
5237  *     };
5238  *     return directiveDefinitionObject;
5239  *     // or
5240  *     // return function postLink(scope, iElement, iAttrs) { ... }
5241  *   });
5242  * ```
5243  *
5244  *
5245  *
5246  * ### Directive Definition Object
5247  *
5248  * The directive definition object provides instructions to the {@link ng.$compile
5249  * compiler}. The attributes are:
5250  *
5251  * #### `priority`
5252  * When there are multiple directives defined on a single DOM element, sometimes it
5253  * is necessary to specify the order in which the directives are applied. The `priority` is used
5254  * to sort the directives before their `compile` functions get called. Priority is defined as a
5255  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5256  * are also run in priority order, but post-link functions are run in reverse order. The order
5257  * of directives with the same priority is undefined. The default priority is `0`.
5258  *
5259  * #### `terminal`
5260  * If set to true then the current `priority` will be the last set of directives
5261  * which will execute (any directives at the current priority will still execute
5262  * as the order of execution on same `priority` is undefined).
5263  *
5264  * #### `scope`
5265  * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5266  * same element request a new scope, only one new scope is created. The new scope rule does not
5267  * apply for the root of the template since the root of the template always gets a new scope.
5268  *
5269  * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5270  * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5271  * when creating reusable components, which should not accidentally read or modify data in the
5272  * parent scope.
5273  *
5274  * The 'isolate' scope takes an object hash which defines a set of local scope properties
5275  * derived from the parent scope. These local properties are useful for aliasing values for
5276  * templates. Locals definition is a hash of local scope property to its source:
5277  *
5278  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5279  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5280  *   attribute name is assumed to be the same as the local name.
5281  *   Given `<widget my-attr="hello {{name}}">` and widget definition
5282  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5283  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5284  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5285  *   component scope).
5286  *
5287  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5288  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5289  *   name is specified then the attribute name is assumed to be the same as the local name.
5290  *   Given `<widget my-attr="parentModel">` and widget definition of
5291  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5292  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5293  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5294  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5295  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5296  *
5297  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5298  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5299  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5300  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5301  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5302  *   pass data from the isolated scope via an expression to the parent scope, this can be
5303  *   done by passing a map of local variable names and values into the expression wrapper fn.
5304  *   For example, if the expression is `increment(amount)` then we can specify the amount value
5305  *   by calling the `localFn` as `localFn({amount: 22})`.
5306  *
5307  *
5308  *
5309  * #### `controller`
5310  * Controller constructor function. The controller is instantiated before the
5311  * pre-linking phase and it is shared with other directives (see
5312  * `require` attribute). This allows the directives to communicate with each other and augment
5313  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5314  *
5315  * * `$scope` - Current scope associated with the element
5316  * * `$element` - Current element
5317  * * `$attrs` - Current attributes object for the element
5318  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5319  *    The scope can be overridden by an optional first argument.
5320  *   `function([scope], cloneLinkingFn)`.
5321  *
5322  *
5323  * #### `require`
5324  * Require another directive and inject its controller as the fourth argument to the linking function. The
5325  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5326  * injected argument will be an array in corresponding order. If no such directive can be
5327  * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5328  *
5329  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5330  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5331  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5332  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5333  *   `null` to the `link` fn if not found.
5334  *
5335  *
5336  * #### `controllerAs`
5337  * Controller alias at the directive scope. An alias for the controller so it
5338  * can be referenced at the directive template. The directive needs to define a scope for this
5339  * configuration to be used. Useful in the case when directive is used as component.
5340  *
5341  *
5342  * #### `restrict`
5343  * String of subset of `EACM` which restricts the directive to a specific directive
5344  * declaration style. If omitted, the default (attributes only) is used.
5345  *
5346  * * `E` - Element name: `<my-directive></my-directive>`
5347  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5348  * * `C` - Class: `<div class="my-directive: exp;"></div>`
5349  * * `M` - Comment: `<!-- directive: my-directive exp -->`
5350  *
5351  *
5352  * #### `template`
5353  * HTML markup that may:
5354  * * Replace the contents of the directive's element (default).
5355  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
5356  * * Wrap the contents of the directive's element (if `transclude` is true).
5357  *
5358  * Value may be:
5359  *
5360  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
5361  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
5362  *   function api below) and returns a string value.
5363  *
5364  *
5365  * #### `templateUrl`
5366  * Same as `template` but the template is loaded from the specified URL. Because
5367  * the template loading is asynchronous the compilation/linking is suspended until the template
5368  * is loaded.
5369  *
5370  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5371  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5372  * a string value representing the url.  In either case, the template URL is passed through {@link
5373  * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5374  *
5375  *
5376  * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
5377  * specify what the template should replace. Defaults to `false`.
5378  *
5379  * * `true` - the template will replace the directive's element.
5380  * * `false` - the template will replace the contents of the directive's element.
5381  *
5382  * The replacement process migrates all of the attributes / classes from the old element to the new
5383  * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5384  * Directives Guide} for an example.
5385  *
5386  * #### `transclude`
5387  * compile the content of the element and make it available to the directive.
5388  * Typically used with {@link ng.directive:ngTransclude
5389  * ngTransclude}. The advantage of transclusion is that the linking function receives a
5390  * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5391  * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5392  * scope. This makes it possible for the widget to have private state, and the transclusion to
5393  * be bound to the parent (pre-`isolate`) scope.
5394  *
5395  * * `true` - transclude the content of the directive.
5396  * * `'element'` - transclude the whole element including any directives defined at lower priority.
5397  *
5398  * <div class="alert alert-warning">
5399  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
5400  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
5401  * Testing Transclusion Directives}.
5402  * </div>
5403  *
5404  * #### `compile`
5405  *
5406  * ```js
5407  *   function compile(tElement, tAttrs, transclude) { ... }
5408  * ```
5409  *
5410  * The compile function deals with transforming the template DOM. Since most directives do not do
5411  * template transformation, it is not used often. The compile function takes the following arguments:
5412  *
5413  *   * `tElement` - template element - The element where the directive has been declared. It is
5414  *     safe to do template transformation on the element and child elements only.
5415  *
5416  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5417  *     between all directive compile functions.
5418  *
5419  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5420  *
5421  * <div class="alert alert-warning">
5422  * **Note:** The template instance and the link instance may be different objects if the template has
5423  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5424  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5425  * should be done in a linking function rather than in a compile function.
5426  * </div>
5427
5428  * <div class="alert alert-warning">
5429  * **Note:** The compile function cannot handle directives that recursively use themselves in their
5430  * own templates or compile functions. Compiling these directives results in an infinite loop and a
5431  * stack overflow errors.
5432  *
5433  * This can be avoided by manually using $compile in the postLink function to imperatively compile
5434  * a directive's template instead of relying on automatic template compilation via `template` or
5435  * `templateUrl` declaration or manual compilation inside the compile function.
5436  * </div>
5437  *
5438  * <div class="alert alert-error">
5439  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5440  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5441  *   to the link function instead.
5442  * </div>
5443
5444  * A compile function can have a return value which can be either a function or an object.
5445  *
5446  * * returning a (post-link) function - is equivalent to registering the linking function via the
5447  *   `link` property of the config object when the compile function is empty.
5448  *
5449  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5450  *   control when a linking function should be called during the linking phase. See info about
5451  *   pre-linking and post-linking functions below.
5452  *
5453  *
5454  * #### `link`
5455  * This property is used only if the `compile` property is not defined.
5456  *
5457  * ```js
5458  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5459  * ```
5460  *
5461  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5462  * executed after the template has been cloned. This is where most of the directive logic will be
5463  * put.
5464  *
5465  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5466  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5467  *
5468  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5469  *     manipulate the children of the element only in `postLink` function since the children have
5470  *     already been linked.
5471  *
5472  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5473  *     between all directive linking functions.
5474  *
5475  *   * `controller` - a controller instance - A controller instance if at least one directive on the
5476  *     element defines a controller. The controller is shared among all the directives, which allows
5477  *     the directives to use the controllers as a communication channel.
5478  *
5479  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5480  *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5481  *     parameter of directive controllers.
5482  *     `function([scope], cloneLinkingFn)`.
5483  *
5484  *
5485  * #### Pre-linking function
5486  *
5487  * Executed before the child elements are linked. Not safe to do DOM transformation since the
5488  * compiler linking function will fail to locate the correct elements for linking.
5489  *
5490  * #### Post-linking function
5491  *
5492  * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5493  *
5494  * <a name="Attributes"></a>
5495  * ### Attributes
5496  *
5497  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5498  * `link()` or `compile()` functions. It has a variety of uses.
5499  *
5500  * accessing *Normalized attribute names:*
5501  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5502  * the attributes object allows for normalized access to
5503  *   the attributes.
5504  *
5505  * * *Directive inter-communication:* All directives share the same instance of the attributes
5506  *   object which allows the directives to use the attributes object as inter directive
5507  *   communication.
5508  *
5509  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5510  *   allowing other directives to read the interpolated value.
5511  *
5512  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5513  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
5514  *   the only way to easily get the actual value because during the linking phase the interpolation
5515  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5516  *
5517  * ```js
5518  * function linkingFn(scope, elm, attrs, ctrl) {
5519  *   // get the attribute value
5520  *   console.log(attrs.ngModel);
5521  *
5522  *   // change the attribute
5523  *   attrs.$set('ngModel', 'new value');
5524  *
5525  *   // observe changes to interpolated attribute
5526  *   attrs.$observe('ngModel', function(value) {
5527  *     console.log('ngModel has changed value to ' + value);
5528  *   });
5529  * }
5530  * ```
5531  *
5532  * Below is an example using `$compileProvider`.
5533  *
5534  * <div class="alert alert-warning">
5535  * **Note**: Typically directives are registered with `module.directive`. The example below is
5536  * to illustrate how `$compile` works.
5537  * </div>
5538  *
5539  <example module="compileExample">
5540    <file name="index.html">
5541     <script>
5542       angular.module('compileExample', [], function($compileProvider) {
5543         // configure new 'compile' directive by passing a directive
5544         // factory function. The factory function injects the '$compile'
5545         $compileProvider.directive('compile', function($compile) {
5546           // directive factory creates a link function
5547           return function(scope, element, attrs) {
5548             scope.$watch(
5549               function(scope) {
5550                  // watch the 'compile' expression for changes
5551                 return scope.$eval(attrs.compile);
5552               },
5553               function(value) {
5554                 // when the 'compile' expression changes
5555                 // assign it into the current DOM
5556                 element.html(value);
5557
5558                 // compile the new DOM and link it to the current
5559                 // scope.
5560                 // NOTE: we only compile .childNodes so that
5561                 // we don't get into infinite loop compiling ourselves
5562                 $compile(element.contents())(scope);
5563               }
5564             );
5565           };
5566         });
5567       })
5568       .controller('GreeterController', ['$scope', function($scope) {
5569         $scope.name = 'Angular';
5570         $scope.html = 'Hello {{name}}';
5571       }]);
5572     </script>
5573     <div ng-controller="GreeterController">
5574       <input ng-model="name"> <br>
5575       <textarea ng-model="html"></textarea> <br>
5576       <div compile="html"></div>
5577     </div>
5578    </file>
5579    <file name="protractor.js" type="protractor">
5580      it('should auto compile', function() {
5581        var textarea = $('textarea');
5582        var output = $('div[compile]');
5583        // The initial state reads 'Hello Angular'.
5584        expect(output.getText()).toBe('Hello Angular');
5585        textarea.clear();
5586        textarea.sendKeys('{{name}}!');
5587        expect(output.getText()).toBe('Angular!');
5588      });
5589    </file>
5590  </example>
5591
5592  *
5593  *
5594  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5595  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5596  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5597  *                 root element(s), not their children)
5598  * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5599  * (a DOM element/tree) to a scope. Where:
5600  *
5601  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5602  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5603  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5604  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5605  *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5606  *
5607  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5608  *      * `scope` - is the current scope with which the linking function is working with.
5609  *
5610  * Calling the linking function returns the element of the template. It is either the original
5611  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5612  *
5613  * After linking the view is not updated until after a call to $digest which typically is done by
5614  * Angular automatically.
5615  *
5616  * If you need access to the bound view, there are two ways to do it:
5617  *
5618  * - If you are not asking the linking function to clone the template, create the DOM element(s)
5619  *   before you send them to the compiler and keep this reference around.
5620  *   ```js
5621  *     var element = $compile('<p>{{total}}</p>')(scope);
5622  *   ```
5623  *
5624  * - if on the other hand, you need the element to be cloned, the view reference from the original
5625  *   example would not point to the clone, but rather to the original template that was cloned. In
5626  *   this case, you can access the clone via the cloneAttachFn:
5627  *   ```js
5628  *     var templateElement = angular.element('<p>{{total}}</p>'),
5629  *         scope = ....;
5630  *
5631  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5632  *       //attach the clone to DOM document at the right place
5633  *     });
5634  *
5635  *     //now we have reference to the cloned DOM via `clonedElement`
5636  *   ```
5637  *
5638  *
5639  * For information on how the compiler works, see the
5640  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5641  */
5642
5643 var $compileMinErr = minErr('$compile');
5644
5645 /**
5646  * @ngdoc provider
5647  * @name $compileProvider
5648  * @kind function
5649  *
5650  * @description
5651  */
5652 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5653 function $CompileProvider($provide, $$sanitizeUriProvider) {
5654   var hasDirectives = {},
5655       Suffix = 'Directive',
5656       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
5657       CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
5658
5659   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5660   // The assumption is that future DOM event attribute names will begin with
5661   // 'on' and be composed of only English letters.
5662   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5663
5664   /**
5665    * @ngdoc method
5666    * @name $compileProvider#directive
5667    * @kind function
5668    *
5669    * @description
5670    * Register a new directive with the compiler.
5671    *
5672    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5673    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5674    *    names and the values are the factories.
5675    * @param {Function|Array} directiveFactory An injectable directive factory function. See
5676    *    {@link guide/directive} for more info.
5677    * @returns {ng.$compileProvider} Self for chaining.
5678    */
5679    this.directive = function registerDirective(name, directiveFactory) {
5680     assertNotHasOwnProperty(name, 'directive');
5681     if (isString(name)) {
5682       assertArg(directiveFactory, 'directiveFactory');
5683       if (!hasDirectives.hasOwnProperty(name)) {
5684         hasDirectives[name] = [];
5685         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5686           function($injector, $exceptionHandler) {
5687             var directives = [];
5688             forEach(hasDirectives[name], function(directiveFactory, index) {
5689               try {
5690                 var directive = $injector.invoke(directiveFactory);
5691                 if (isFunction(directive)) {
5692                   directive = { compile: valueFn(directive) };
5693                 } else if (!directive.compile && directive.link) {
5694                   directive.compile = valueFn(directive.link);
5695                 }
5696                 directive.priority = directive.priority || 0;
5697                 directive.index = index;
5698                 directive.name = directive.name || name;
5699                 directive.require = directive.require || (directive.controller && directive.name);
5700                 directive.restrict = directive.restrict || 'A';
5701                 directives.push(directive);
5702               } catch (e) {
5703                 $exceptionHandler(e);
5704               }
5705             });
5706             return directives;
5707           }]);
5708       }
5709       hasDirectives[name].push(directiveFactory);
5710     } else {
5711       forEach(name, reverseParams(registerDirective));
5712     }
5713     return this;
5714   };
5715
5716
5717   /**
5718    * @ngdoc method
5719    * @name $compileProvider#aHrefSanitizationWhitelist
5720    * @kind function
5721    *
5722    * @description
5723    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5724    * urls during a[href] sanitization.
5725    *
5726    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5727    *
5728    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5729    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5730    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5731    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5732    *
5733    * @param {RegExp=} regexp New regexp to whitelist urls with.
5734    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5735    *    chaining otherwise.
5736    */
5737   this.aHrefSanitizationWhitelist = function(regexp) {
5738     if (isDefined(regexp)) {
5739       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5740       return this;
5741     } else {
5742       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5743     }
5744   };
5745
5746
5747   /**
5748    * @ngdoc method
5749    * @name $compileProvider#imgSrcSanitizationWhitelist
5750    * @kind function
5751    *
5752    * @description
5753    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5754    * urls during img[src] sanitization.
5755    *
5756    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5757    *
5758    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5759    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5760    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5761    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5762    *
5763    * @param {RegExp=} regexp New regexp to whitelist urls with.
5764    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5765    *    chaining otherwise.
5766    */
5767   this.imgSrcSanitizationWhitelist = function(regexp) {
5768     if (isDefined(regexp)) {
5769       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5770       return this;
5771     } else {
5772       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5773     }
5774   };
5775
5776   this.$get = [
5777             '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5778             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5779     function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5780              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5781
5782     var Attributes = function(element, attr) {
5783       this.$$element = element;
5784       this.$attr = attr || {};
5785     };
5786
5787     Attributes.prototype = {
5788       $normalize: directiveNormalize,
5789
5790
5791       /**
5792        * @ngdoc method
5793        * @name $compile.directive.Attributes#$addClass
5794        * @kind function
5795        *
5796        * @description
5797        * Adds the CSS class value specified by the classVal parameter to the element. If animations
5798        * are enabled then an animation will be triggered for the class addition.
5799        *
5800        * @param {string} classVal The className value that will be added to the element
5801        */
5802       $addClass : function(classVal) {
5803         if(classVal && classVal.length > 0) {
5804           $animate.addClass(this.$$element, classVal);
5805         }
5806       },
5807
5808       /**
5809        * @ngdoc method
5810        * @name $compile.directive.Attributes#$removeClass
5811        * @kind function
5812        *
5813        * @description
5814        * Removes the CSS class value specified by the classVal parameter from the element. If
5815        * animations are enabled then an animation will be triggered for the class removal.
5816        *
5817        * @param {string} classVal The className value that will be removed from the element
5818        */
5819       $removeClass : function(classVal) {
5820         if(classVal && classVal.length > 0) {
5821           $animate.removeClass(this.$$element, classVal);
5822         }
5823       },
5824
5825       /**
5826        * @ngdoc method
5827        * @name $compile.directive.Attributes#$updateClass
5828        * @kind function
5829        *
5830        * @description
5831        * Adds and removes the appropriate CSS class values to the element based on the difference
5832        * between the new and old CSS class values (specified as newClasses and oldClasses).
5833        *
5834        * @param {string} newClasses The current CSS className value
5835        * @param {string} oldClasses The former CSS className value
5836        */
5837       $updateClass : function(newClasses, oldClasses) {
5838         var toAdd = tokenDifference(newClasses, oldClasses);
5839         var toRemove = tokenDifference(oldClasses, newClasses);
5840
5841         if(toAdd.length === 0) {
5842           $animate.removeClass(this.$$element, toRemove);
5843         } else if(toRemove.length === 0) {
5844           $animate.addClass(this.$$element, toAdd);
5845         } else {
5846           $animate.setClass(this.$$element, toAdd, toRemove);
5847         }
5848       },
5849
5850       /**
5851        * Set a normalized attribute on the element in a way such that all directives
5852        * can share the attribute. This function properly handles boolean attributes.
5853        * @param {string} key Normalized key. (ie ngAttribute)
5854        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5855        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5856        *     Defaults to true.
5857        * @param {string=} attrName Optional none normalized name. Defaults to key.
5858        */
5859       $set: function(key, value, writeAttr, attrName) {
5860         // TODO: decide whether or not to throw an error if "class"
5861         //is set through this function since it may cause $updateClass to
5862         //become unstable.
5863
5864         var booleanKey = getBooleanAttrName(this.$$element[0], key),
5865             normalizedVal,
5866             nodeName;
5867
5868         if (booleanKey) {
5869           this.$$element.prop(key, value);
5870           attrName = booleanKey;
5871         }
5872
5873         this[key] = value;
5874
5875         // translate normalized key to actual key
5876         if (attrName) {
5877           this.$attr[key] = attrName;
5878         } else {
5879           attrName = this.$attr[key];
5880           if (!attrName) {
5881             this.$attr[key] = attrName = snake_case(key, '-');
5882           }
5883         }
5884
5885         nodeName = nodeName_(this.$$element);
5886
5887         // sanitize a[href] and img[src] values
5888         if ((nodeName === 'A' && key === 'href') ||
5889             (nodeName === 'IMG' && key === 'src')) {
5890           this[key] = value = $$sanitizeUri(value, key === 'src');
5891         }
5892
5893         if (writeAttr !== false) {
5894           if (value === null || value === undefined) {
5895             this.$$element.removeAttr(attrName);
5896           } else {
5897             this.$$element.attr(attrName, value);
5898           }
5899         }
5900
5901         // fire observers
5902         var $$observers = this.$$observers;
5903         $$observers && forEach($$observers[key], function(fn) {
5904           try {
5905             fn(value);
5906           } catch (e) {
5907             $exceptionHandler(e);
5908           }
5909         });
5910       },
5911
5912
5913       /**
5914        * @ngdoc method
5915        * @name $compile.directive.Attributes#$observe
5916        * @kind function
5917        *
5918        * @description
5919        * Observes an interpolated attribute.
5920        *
5921        * The observer function will be invoked once during the next `$digest` following
5922        * compilation. The observer is then invoked whenever the interpolated value
5923        * changes.
5924        *
5925        * @param {string} key Normalized key. (ie ngAttribute) .
5926        * @param {function(interpolatedValue)} fn Function that will be called whenever
5927                 the interpolated value of the attribute changes.
5928        *        See the {@link guide/directive#Attributes Directives} guide for more info.
5929        * @returns {function()} the `fn` parameter.
5930        */
5931       $observe: function(key, fn) {
5932         var attrs = this,
5933             $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5934             listeners = ($$observers[key] || ($$observers[key] = []));
5935
5936         listeners.push(fn);
5937         $rootScope.$evalAsync(function() {
5938           if (!listeners.$$inter) {
5939             // no one registered attribute interpolation function, so lets call it manually
5940             fn(attrs[key]);
5941           }
5942         });
5943         return fn;
5944       }
5945     };
5946
5947     var startSymbol = $interpolate.startSymbol(),
5948         endSymbol = $interpolate.endSymbol(),
5949         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5950             ? identity
5951             : function denormalizeTemplate(template) {
5952               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5953         },
5954         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5955
5956
5957     return compile;
5958
5959     //================================
5960
5961     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5962                         previousCompileContext) {
5963       if (!($compileNodes instanceof jqLite)) {
5964         // jquery always rewraps, whereas we need to preserve the original selector so that we can
5965         // modify it.
5966         $compileNodes = jqLite($compileNodes);
5967       }
5968       // We can not compile top level text elements since text nodes can be merged and we will
5969       // not be able to attach scope data to them, so we will wrap them in <span>
5970       forEach($compileNodes, function(node, index){
5971         if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5972           $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5973         }
5974       });
5975       var compositeLinkFn =
5976               compileNodes($compileNodes, transcludeFn, $compileNodes,
5977                            maxPriority, ignoreDirective, previousCompileContext);
5978       safeAddClass($compileNodes, 'ng-scope');
5979       return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
5980         assertArg(scope, 'scope');
5981         // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5982         // and sometimes changes the structure of the DOM.
5983         var $linkNode = cloneConnectFn
5984           ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5985           : $compileNodes;
5986
5987         forEach(transcludeControllers, function(instance, name) {
5988           $linkNode.data('$' + name + 'Controller', instance);
5989         });
5990
5991         // Attach scope only to non-text nodes.
5992         for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5993           var node = $linkNode[i],
5994               nodeType = node.nodeType;
5995           if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5996             $linkNode.eq(i).data('$scope', scope);
5997           }
5998         }
5999
6000         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
6001         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
6002         return $linkNode;
6003       };
6004     }
6005
6006     function safeAddClass($element, className) {
6007       try {
6008         $element.addClass(className);
6009       } catch(e) {
6010         // ignore, since it means that we are trying to set class on
6011         // SVG element, where class name is read-only.
6012       }
6013     }
6014
6015     /**
6016      * Compile function matches each node in nodeList against the directives. Once all directives
6017      * for a particular node are collected their compile functions are executed. The compile
6018      * functions return values - the linking functions - are combined into a composite linking
6019      * function, which is the a linking function for the node.
6020      *
6021      * @param {NodeList} nodeList an array of nodes or NodeList to compile
6022      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6023      *        scope argument is auto-generated to the new child of the transcluded parent scope.
6024      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
6025      *        the rootElement must be set the jqLite collection of the compile root. This is
6026      *        needed so that the jqLite collection items can be replaced with widgets.
6027      * @param {number=} maxPriority Max directive priority.
6028      * @returns {Function} A composite linking function of all of the matched directives or null.
6029      */
6030     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
6031                             previousCompileContext) {
6032       var linkFns = [],
6033           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
6034
6035       for (var i = 0; i < nodeList.length; i++) {
6036         attrs = new Attributes();
6037
6038         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
6039         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
6040                                         ignoreDirective);
6041
6042         nodeLinkFn = (directives.length)
6043             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
6044                                       null, [], [], previousCompileContext)
6045             : null;
6046
6047         if (nodeLinkFn && nodeLinkFn.scope) {
6048           safeAddClass(attrs.$$element, 'ng-scope');
6049         }
6050
6051         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
6052                       !(childNodes = nodeList[i].childNodes) ||
6053                       !childNodes.length)
6054             ? null
6055             : compileNodes(childNodes,
6056                  nodeLinkFn ? (
6057                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
6058                      && nodeLinkFn.transclude) : transcludeFn);
6059
6060         linkFns.push(nodeLinkFn, childLinkFn);
6061         linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
6062         //use the previous context only for the first element in the virtual group
6063         previousCompileContext = null;
6064       }
6065
6066       // return a linking function if we have found anything, null otherwise
6067       return linkFnFound ? compositeLinkFn : null;
6068
6069       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
6070         var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
6071
6072         // copy nodeList so that linking doesn't break due to live list updates.
6073         var nodeListLength = nodeList.length,
6074             stableNodeList = new Array(nodeListLength);
6075         for (i = 0; i < nodeListLength; i++) {
6076           stableNodeList[i] = nodeList[i];
6077         }
6078
6079         for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
6080           node = stableNodeList[n];
6081           nodeLinkFn = linkFns[i++];
6082           childLinkFn = linkFns[i++];
6083
6084           if (nodeLinkFn) {
6085             if (nodeLinkFn.scope) {
6086               childScope = scope.$new();
6087               jqLite.data(node, '$scope', childScope);
6088             } else {
6089               childScope = scope;
6090             }
6091
6092             if ( nodeLinkFn.transcludeOnThisElement ) {
6093               childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
6094
6095             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
6096               childBoundTranscludeFn = parentBoundTranscludeFn;
6097
6098             } else if (!parentBoundTranscludeFn && transcludeFn) {
6099               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
6100
6101             } else {
6102               childBoundTranscludeFn = null;
6103             }
6104
6105             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
6106
6107           } else if (childLinkFn) {
6108             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
6109           }
6110         }
6111       }
6112     }
6113
6114     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
6115
6116       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
6117         var scopeCreated = false;
6118
6119         if (!transcludedScope) {
6120           transcludedScope = scope.$new();
6121           transcludedScope.$$transcluded = true;
6122           scopeCreated = true;
6123         }
6124
6125         var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
6126         if (scopeCreated) {
6127           clone.on('$destroy', function() { transcludedScope.$destroy(); });
6128         }
6129         return clone;
6130       };
6131
6132       return boundTranscludeFn;
6133     }
6134
6135     /**
6136      * Looks for directives on the given node and adds them to the directive collection which is
6137      * sorted.
6138      *
6139      * @param node Node to search.
6140      * @param directives An array to which the directives are added to. This array is sorted before
6141      *        the function returns.
6142      * @param attrs The shared attrs object which is used to populate the normalized attributes.
6143      * @param {number=} maxPriority Max directive priority.
6144      */
6145     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6146       var nodeType = node.nodeType,
6147           attrsMap = attrs.$attr,
6148           match,
6149           className;
6150
6151       switch(nodeType) {
6152         case 1: /* Element */
6153           // use the node name: <directive>
6154           addDirective(directives,
6155               directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6156
6157           // iterate over the attributes
6158           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
6159                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6160             var attrStartName = false;
6161             var attrEndName = false;
6162
6163             attr = nAttrs[j];
6164             if (!msie || msie >= 8 || attr.specified) {
6165               name = attr.name;
6166               value = trim(attr.value);
6167
6168               // support ngAttr attribute binding
6169               ngAttrName = directiveNormalize(name);
6170               if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
6171                 name = snake_case(ngAttrName.substr(6), '-');
6172               }
6173
6174               var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6175               if (ngAttrName === directiveNName + 'Start') {
6176                 attrStartName = name;
6177                 attrEndName = name.substr(0, name.length - 5) + 'end';
6178                 name = name.substr(0, name.length - 6);
6179               }
6180
6181               nName = directiveNormalize(name.toLowerCase());
6182               attrsMap[nName] = name;
6183               if (isNgAttr || !attrs.hasOwnProperty(nName)) {
6184                   attrs[nName] = value;
6185                   if (getBooleanAttrName(node, nName)) {
6186                     attrs[nName] = true; // presence means true
6187                   }
6188               }
6189               addAttrInterpolateDirective(node, directives, value, nName);
6190               addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6191                             attrEndName);
6192             }
6193           }
6194
6195           // use class as directive
6196           className = node.className;
6197           if (isString(className) && className !== '') {
6198             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6199               nName = directiveNormalize(match[2]);
6200               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6201                 attrs[nName] = trim(match[3]);
6202               }
6203               className = className.substr(match.index + match[0].length);
6204             }
6205           }
6206           break;
6207         case 3: /* Text Node */
6208           addTextInterpolateDirective(directives, node.nodeValue);
6209           break;
6210         case 8: /* Comment */
6211           try {
6212             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6213             if (match) {
6214               nName = directiveNormalize(match[1]);
6215               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6216                 attrs[nName] = trim(match[2]);
6217               }
6218             }
6219           } catch (e) {
6220             // turns out that under some circumstances IE9 throws errors when one attempts to read
6221             // comment's node value.
6222             // Just ignore it and continue. (Can't seem to reproduce in test case.)
6223           }
6224           break;
6225       }
6226
6227       directives.sort(byPriority);
6228       return directives;
6229     }
6230
6231     /**
6232      * Given a node with an directive-start it collects all of the siblings until it finds
6233      * directive-end.
6234      * @param node
6235      * @param attrStart
6236      * @param attrEnd
6237      * @returns {*}
6238      */
6239     function groupScan(node, attrStart, attrEnd) {
6240       var nodes = [];
6241       var depth = 0;
6242       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6243         var startNode = node;
6244         do {
6245           if (!node) {
6246             throw $compileMinErr('uterdir',
6247                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6248                       attrStart, attrEnd);
6249           }
6250           if (node.nodeType == 1 /** Element **/) {
6251             if (node.hasAttribute(attrStart)) depth++;
6252             if (node.hasAttribute(attrEnd)) depth--;
6253           }
6254           nodes.push(node);
6255           node = node.nextSibling;
6256         } while (depth > 0);
6257       } else {
6258         nodes.push(node);
6259       }
6260
6261       return jqLite(nodes);
6262     }
6263
6264     /**
6265      * Wrapper for linking function which converts normal linking function into a grouped
6266      * linking function.
6267      * @param linkFn
6268      * @param attrStart
6269      * @param attrEnd
6270      * @returns {Function}
6271      */
6272     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6273       return function(scope, element, attrs, controllers, transcludeFn) {
6274         element = groupScan(element[0], attrStart, attrEnd);
6275         return linkFn(scope, element, attrs, controllers, transcludeFn);
6276       };
6277     }
6278
6279     /**
6280      * Once the directives have been collected, their compile functions are executed. This method
6281      * is responsible for inlining directive templates as well as terminating the application
6282      * of the directives if the terminal directive has been reached.
6283      *
6284      * @param {Array} directives Array of collected directives to execute their compile function.
6285      *        this needs to be pre-sorted by priority order.
6286      * @param {Node} compileNode The raw DOM node to apply the compile functions to
6287      * @param {Object} templateAttrs The shared attribute function
6288      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6289      *                                                  scope argument is auto-generated to the new
6290      *                                                  child of the transcluded parent scope.
6291      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6292      *                              argument has the root jqLite array so that we can replace nodes
6293      *                              on it.
6294      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6295      *                                           compiling the transclusion.
6296      * @param {Array.<Function>} preLinkFns
6297      * @param {Array.<Function>} postLinkFns
6298      * @param {Object} previousCompileContext Context used for previous compilation of the current
6299      *                                        node
6300      * @returns {Function} linkFn
6301      */
6302     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
6303                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
6304                                    previousCompileContext) {
6305       previousCompileContext = previousCompileContext || {};
6306
6307       var terminalPriority = -Number.MAX_VALUE,
6308           newScopeDirective,
6309           controllerDirectives = previousCompileContext.controllerDirectives,
6310           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6311           templateDirective = previousCompileContext.templateDirective,
6312           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6313           hasTranscludeDirective = false,
6314           hasTemplate = false,
6315           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6316           $compileNode = templateAttrs.$$element = jqLite(compileNode),
6317           directive,
6318           directiveName,
6319           $template,
6320           replaceDirective = originalReplaceDirective,
6321           childTranscludeFn = transcludeFn,
6322           linkFn,
6323           directiveValue;
6324
6325       // executes all directives on the current element
6326       for(var i = 0, ii = directives.length; i < ii; i++) {
6327         directive = directives[i];
6328         var attrStart = directive.$$start;
6329         var attrEnd = directive.$$end;
6330
6331         // collect multiblock sections
6332         if (attrStart) {
6333           $compileNode = groupScan(compileNode, attrStart, attrEnd);
6334         }
6335         $template = undefined;
6336
6337         if (terminalPriority > directive.priority) {
6338           break; // prevent further processing of directives
6339         }
6340
6341         if (directiveValue = directive.scope) {
6342           newScopeDirective = newScopeDirective || directive;
6343
6344           // skip the check for directives with async templates, we'll check the derived sync
6345           // directive when the template arrives
6346           if (!directive.templateUrl) {
6347             assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6348                               $compileNode);
6349             if (isObject(directiveValue)) {
6350               newIsolateScopeDirective = directive;
6351             }
6352           }
6353         }
6354
6355         directiveName = directive.name;
6356
6357         if (!directive.templateUrl && directive.controller) {
6358           directiveValue = directive.controller;
6359           controllerDirectives = controllerDirectives || {};
6360           assertNoDuplicate("'" + directiveName + "' controller",
6361               controllerDirectives[directiveName], directive, $compileNode);
6362           controllerDirectives[directiveName] = directive;
6363         }
6364
6365         if (directiveValue = directive.transclude) {
6366           hasTranscludeDirective = true;
6367
6368           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6369           // This option should only be used by directives that know how to safely handle element transclusion,
6370           // where the transcluded nodes are added or replaced after linking.
6371           if (!directive.$$tlb) {
6372             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6373             nonTlbTranscludeDirective = directive;
6374           }
6375
6376           if (directiveValue == 'element') {
6377             hasElementTranscludeDirective = true;
6378             terminalPriority = directive.priority;
6379             $template = $compileNode;
6380             $compileNode = templateAttrs.$$element =
6381                 jqLite(document.createComment(' ' + directiveName + ': ' +
6382                                               templateAttrs[directiveName] + ' '));
6383             compileNode = $compileNode[0];
6384             replaceWith(jqCollection, sliceArgs($template), compileNode);
6385
6386             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6387                                         replaceDirective && replaceDirective.name, {
6388                                           // Don't pass in:
6389                                           // - controllerDirectives - otherwise we'll create duplicates controllers
6390                                           // - newIsolateScopeDirective or templateDirective - combining templates with
6391                                           //   element transclusion doesn't make sense.
6392                                           //
6393                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6394                                           // on the same element more than once.
6395                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
6396                                         });
6397           } else {
6398             $template = jqLite(jqLiteClone(compileNode)).contents();
6399             $compileNode.empty(); // clear contents
6400             childTranscludeFn = compile($template, transcludeFn);
6401           }
6402         }
6403
6404         if (directive.template) {
6405           hasTemplate = true;
6406           assertNoDuplicate('template', templateDirective, directive, $compileNode);
6407           templateDirective = directive;
6408
6409           directiveValue = (isFunction(directive.template))
6410               ? directive.template($compileNode, templateAttrs)
6411               : directive.template;
6412
6413           directiveValue = denormalizeTemplate(directiveValue);
6414
6415           if (directive.replace) {
6416             replaceDirective = directive;
6417             if (jqLiteIsTextNode(directiveValue)) {
6418               $template = [];
6419             } else {
6420               $template = jqLite(trim(directiveValue));
6421             }
6422             compileNode = $template[0];
6423
6424             if ($template.length != 1 || compileNode.nodeType !== 1) {
6425               throw $compileMinErr('tplrt',
6426                   "Template for directive '{0}' must have exactly one root element. {1}",
6427                   directiveName, '');
6428             }
6429
6430             replaceWith(jqCollection, $compileNode, compileNode);
6431
6432             var newTemplateAttrs = {$attr: {}};
6433
6434             // combine directives from the original node and from the template:
6435             // - take the array of directives for this element
6436             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6437             // - collect directives from the template and sort them by priority
6438             // - combine directives as: processed + template + unprocessed
6439             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6440             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6441
6442             if (newIsolateScopeDirective) {
6443               markDirectivesAsIsolate(templateDirectives);
6444             }
6445             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6446             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6447
6448             ii = directives.length;
6449           } else {
6450             $compileNode.html(directiveValue);
6451           }
6452         }
6453
6454         if (directive.templateUrl) {
6455           hasTemplate = true;
6456           assertNoDuplicate('template', templateDirective, directive, $compileNode);
6457           templateDirective = directive;
6458
6459           if (directive.replace) {
6460             replaceDirective = directive;
6461           }
6462
6463           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6464               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
6465                 controllerDirectives: controllerDirectives,
6466                 newIsolateScopeDirective: newIsolateScopeDirective,
6467                 templateDirective: templateDirective,
6468                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
6469               });
6470           ii = directives.length;
6471         } else if (directive.compile) {
6472           try {
6473             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6474             if (isFunction(linkFn)) {
6475               addLinkFns(null, linkFn, attrStart, attrEnd);
6476             } else if (linkFn) {
6477               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6478             }
6479           } catch (e) {
6480             $exceptionHandler(e, startingTag($compileNode));
6481           }
6482         }
6483
6484         if (directive.terminal) {
6485           nodeLinkFn.terminal = true;
6486           terminalPriority = Math.max(terminalPriority, directive.priority);
6487         }
6488
6489       }
6490
6491       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6492       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
6493       nodeLinkFn.templateOnThisElement = hasTemplate;
6494       nodeLinkFn.transclude = childTranscludeFn;
6495
6496       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6497
6498       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6499       return nodeLinkFn;
6500
6501       ////////////////////
6502
6503       function addLinkFns(pre, post, attrStart, attrEnd) {
6504         if (pre) {
6505           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6506           pre.require = directive.require;
6507           pre.directiveName = directiveName;
6508           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6509             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6510           }
6511           preLinkFns.push(pre);
6512         }
6513         if (post) {
6514           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6515           post.require = directive.require;
6516           post.directiveName = directiveName;
6517           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6518             post = cloneAndAnnotateFn(post, {isolateScope: true});
6519           }
6520           postLinkFns.push(post);
6521         }
6522       }
6523
6524
6525       function getControllers(directiveName, require, $element, elementControllers) {
6526         var value, retrievalMethod = 'data', optional = false;
6527         if (isString(require)) {
6528           while((value = require.charAt(0)) == '^' || value == '?') {
6529             require = require.substr(1);
6530             if (value == '^') {
6531               retrievalMethod = 'inheritedData';
6532             }
6533             optional = optional || value == '?';
6534           }
6535           value = null;
6536
6537           if (elementControllers && retrievalMethod === 'data') {
6538             value = elementControllers[require];
6539           }
6540           value = value || $element[retrievalMethod]('$' + require + 'Controller');
6541
6542           if (!value && !optional) {
6543             throw $compileMinErr('ctreq',
6544                 "Controller '{0}', required by directive '{1}', can't be found!",
6545                 require, directiveName);
6546           }
6547           return value;
6548         } else if (isArray(require)) {
6549           value = [];
6550           forEach(require, function(require) {
6551             value.push(getControllers(directiveName, require, $element, elementControllers));
6552           });
6553         }
6554         return value;
6555       }
6556
6557
6558       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6559         var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6560
6561         attrs = (compileNode === linkNode)
6562           ? templateAttrs
6563           : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6564         $element = attrs.$$element;
6565
6566         if (newIsolateScopeDirective) {
6567           var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6568
6569           isolateScope = scope.$new(true);
6570
6571           if (templateDirective && (templateDirective === newIsolateScopeDirective ||
6572               templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6573             $element.data('$isolateScope', isolateScope);
6574           } else {
6575             $element.data('$isolateScopeNoTemplate', isolateScope);
6576           }
6577
6578
6579
6580           safeAddClass($element, 'ng-isolate-scope');
6581
6582           forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6583             var match = definition.match(LOCAL_REGEXP) || [],
6584                 attrName = match[3] || scopeName,
6585                 optional = (match[2] == '?'),
6586                 mode = match[1], // @, =, or &
6587                 lastValue,
6588                 parentGet, parentSet, compare;
6589
6590             isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6591
6592             switch (mode) {
6593
6594               case '@':
6595                 attrs.$observe(attrName, function(value) {
6596                   isolateScope[scopeName] = value;
6597                 });
6598                 attrs.$$observers[attrName].$$scope = scope;
6599                 if( attrs[attrName] ) {
6600                   // If the attribute has been provided then we trigger an interpolation to ensure
6601                   // the value is there for use in the link fn
6602                   isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6603                 }
6604                 break;
6605
6606               case '=':
6607                 if (optional && !attrs[attrName]) {
6608                   return;
6609                 }
6610                 parentGet = $parse(attrs[attrName]);
6611                 if (parentGet.literal) {
6612                   compare = equals;
6613                 } else {
6614                   compare = function(a,b) { return a === b || (a !== a && b !== b); };
6615                 }
6616                 parentSet = parentGet.assign || function() {
6617                   // reset the change, or we will throw this exception on every $digest
6618                   lastValue = isolateScope[scopeName] = parentGet(scope);
6619                   throw $compileMinErr('nonassign',
6620                       "Expression '{0}' used with directive '{1}' is non-assignable!",
6621                       attrs[attrName], newIsolateScopeDirective.name);
6622                 };
6623                 lastValue = isolateScope[scopeName] = parentGet(scope);
6624                 isolateScope.$watch(function parentValueWatch() {
6625                   var parentValue = parentGet(scope);
6626                   if (!compare(parentValue, isolateScope[scopeName])) {
6627                     // we are out of sync and need to copy
6628                     if (!compare(parentValue, lastValue)) {
6629                       // parent changed and it has precedence
6630                       isolateScope[scopeName] = parentValue;
6631                     } else {
6632                       // if the parent can be assigned then do so
6633                       parentSet(scope, parentValue = isolateScope[scopeName]);
6634                     }
6635                   }
6636                   return lastValue = parentValue;
6637                 }, null, parentGet.literal);
6638                 break;
6639
6640               case '&':
6641                 parentGet = $parse(attrs[attrName]);
6642                 isolateScope[scopeName] = function(locals) {
6643                   return parentGet(scope, locals);
6644                 };
6645                 break;
6646
6647               default:
6648                 throw $compileMinErr('iscp',
6649                     "Invalid isolate scope definition for directive '{0}'." +
6650                     " Definition: {... {1}: '{2}' ...}",
6651                     newIsolateScopeDirective.name, scopeName, definition);
6652             }
6653           });
6654         }
6655         transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6656         if (controllerDirectives) {
6657           forEach(controllerDirectives, function(directive) {
6658             var locals = {
6659               $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6660               $element: $element,
6661               $attrs: attrs,
6662               $transclude: transcludeFn
6663             }, controllerInstance;
6664
6665             controller = directive.controller;
6666             if (controller == '@') {
6667               controller = attrs[directive.name];
6668             }
6669
6670             controllerInstance = $controller(controller, locals);
6671             // For directives with element transclusion the element is a comment,
6672             // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6673             // clean up (http://bugs.jquery.com/ticket/8335).
6674             // Instead, we save the controllers for the element in a local hash and attach to .data
6675             // later, once we have the actual element.
6676             elementControllers[directive.name] = controllerInstance;
6677             if (!hasElementTranscludeDirective) {
6678               $element.data('$' + directive.name + 'Controller', controllerInstance);
6679             }
6680
6681             if (directive.controllerAs) {
6682               locals.$scope[directive.controllerAs] = controllerInstance;
6683             }
6684           });
6685         }
6686
6687         // PRELINKING
6688         for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6689           try {
6690             linkFn = preLinkFns[i];
6691             linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6692                 linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6693           } catch (e) {
6694             $exceptionHandler(e, startingTag($element));
6695           }
6696         }
6697
6698         // RECURSION
6699         // We only pass the isolate scope, if the isolate directive has a template,
6700         // otherwise the child elements do not belong to the isolate directive.
6701         var scopeToChild = scope;
6702         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6703           scopeToChild = isolateScope;
6704         }
6705         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6706
6707         // POSTLINKING
6708         for(i = postLinkFns.length - 1; i >= 0; i--) {
6709           try {
6710             linkFn = postLinkFns[i];
6711             linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6712                 linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6713           } catch (e) {
6714             $exceptionHandler(e, startingTag($element));
6715           }
6716         }
6717
6718         // This is the function that is injected as `$transclude`.
6719         function controllersBoundTransclude(scope, cloneAttachFn) {
6720           var transcludeControllers;
6721
6722           // no scope passed
6723           if (arguments.length < 2) {
6724             cloneAttachFn = scope;
6725             scope = undefined;
6726           }
6727
6728           if (hasElementTranscludeDirective) {
6729             transcludeControllers = elementControllers;
6730           }
6731
6732           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6733         }
6734       }
6735     }
6736
6737     function markDirectivesAsIsolate(directives) {
6738       // mark all directives as needing isolate scope.
6739       for (var j = 0, jj = directives.length; j < jj; j++) {
6740         directives[j] = inherit(directives[j], {$$isolateScope: true});
6741       }
6742     }
6743
6744     /**
6745      * looks up the directive and decorates it with exception handling and proper parameters. We
6746      * call this the boundDirective.
6747      *
6748      * @param {string} name name of the directive to look up.
6749      * @param {string} location The directive must be found in specific format.
6750      *   String containing any of theses characters:
6751      *
6752      *   * `E`: element name
6753      *   * `A': attribute
6754      *   * `C`: class
6755      *   * `M`: comment
6756      * @returns {boolean} true if directive was added.
6757      */
6758     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6759                           endAttrName) {
6760       if (name === ignoreDirective) return null;
6761       var match = null;
6762       if (hasDirectives.hasOwnProperty(name)) {
6763         for(var directive, directives = $injector.get(name + Suffix),
6764             i = 0, ii = directives.length; i<ii; i++) {
6765           try {
6766             directive = directives[i];
6767             if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6768                  directive.restrict.indexOf(location) != -1) {
6769               if (startAttrName) {
6770                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6771               }
6772               tDirectives.push(directive);
6773               match = directive;
6774             }
6775           } catch(e) { $exceptionHandler(e); }
6776         }
6777       }
6778       return match;
6779     }
6780
6781
6782     /**
6783      * When the element is replaced with HTML template then the new attributes
6784      * on the template need to be merged with the existing attributes in the DOM.
6785      * The desired effect is to have both of the attributes present.
6786      *
6787      * @param {object} dst destination attributes (original DOM)
6788      * @param {object} src source attributes (from the directive template)
6789      */
6790     function mergeTemplateAttributes(dst, src) {
6791       var srcAttr = src.$attr,
6792           dstAttr = dst.$attr,
6793           $element = dst.$$element;
6794
6795       // reapply the old attributes to the new element
6796       forEach(dst, function(value, key) {
6797         if (key.charAt(0) != '$') {
6798           if (src[key] && src[key] !== value) {
6799             value += (key === 'style' ? ';' : ' ') + src[key];
6800           }
6801           dst.$set(key, value, true, srcAttr[key]);
6802         }
6803       });
6804
6805       // copy the new attributes on the old attrs object
6806       forEach(src, function(value, key) {
6807         if (key == 'class') {
6808           safeAddClass($element, value);
6809           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6810         } else if (key == 'style') {
6811           $element.attr('style', $element.attr('style') + ';' + value);
6812           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6813           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6814           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6815           // have an attribute like "has-own-property" or "data-has-own-property", etc.
6816         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6817           dst[key] = value;
6818           dstAttr[key] = srcAttr[key];
6819         }
6820       });
6821     }
6822
6823
6824     function compileTemplateUrl(directives, $compileNode, tAttrs,
6825         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6826       var linkQueue = [],
6827           afterTemplateNodeLinkFn,
6828           afterTemplateChildLinkFn,
6829           beforeTemplateCompileNode = $compileNode[0],
6830           origAsyncDirective = directives.shift(),
6831           // The fact that we have to copy and patch the directive seems wrong!
6832           derivedSyncDirective = extend({}, origAsyncDirective, {
6833             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6834           }),
6835           templateUrl = (isFunction(origAsyncDirective.templateUrl))
6836               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
6837               : origAsyncDirective.templateUrl;
6838
6839       $compileNode.empty();
6840
6841       $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6842         success(function(content) {
6843           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6844
6845           content = denormalizeTemplate(content);
6846
6847           if (origAsyncDirective.replace) {
6848             if (jqLiteIsTextNode(content)) {
6849               $template = [];
6850             } else {
6851               $template = jqLite(trim(content));
6852             }
6853             compileNode = $template[0];
6854
6855             if ($template.length != 1 || compileNode.nodeType !== 1) {
6856               throw $compileMinErr('tplrt',
6857                   "Template for directive '{0}' must have exactly one root element. {1}",
6858                   origAsyncDirective.name, templateUrl);
6859             }
6860
6861             tempTemplateAttrs = {$attr: {}};
6862             replaceWith($rootElement, $compileNode, compileNode);
6863             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6864
6865             if (isObject(origAsyncDirective.scope)) {
6866               markDirectivesAsIsolate(templateDirectives);
6867             }
6868             directives = templateDirectives.concat(directives);
6869             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6870           } else {
6871             compileNode = beforeTemplateCompileNode;
6872             $compileNode.html(content);
6873           }
6874
6875           directives.unshift(derivedSyncDirective);
6876
6877           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6878               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6879               previousCompileContext);
6880           forEach($rootElement, function(node, i) {
6881             if (node == compileNode) {
6882               $rootElement[i] = $compileNode[0];
6883             }
6884           });
6885           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6886
6887           while(linkQueue.length) {
6888             var scope = linkQueue.shift(),
6889                 beforeTemplateLinkNode = linkQueue.shift(),
6890                 linkRootElement = linkQueue.shift(),
6891                 boundTranscludeFn = linkQueue.shift(),
6892                 linkNode = $compileNode[0];
6893
6894             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6895               var oldClasses = beforeTemplateLinkNode.className;
6896
6897               if (!(previousCompileContext.hasElementTranscludeDirective &&
6898                   origAsyncDirective.replace)) {
6899                 // it was cloned therefore we have to clone as well.
6900                 linkNode = jqLiteClone(compileNode);
6901               }
6902
6903               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6904
6905               // Copy in CSS classes from original node
6906               safeAddClass(jqLite(linkNode), oldClasses);
6907             }
6908             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6909               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6910             } else {
6911               childBoundTranscludeFn = boundTranscludeFn;
6912             }
6913             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6914               childBoundTranscludeFn);
6915           }
6916           linkQueue = null;
6917         }).
6918         error(function(response, code, headers, config) {
6919           throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6920         });
6921
6922       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6923         var childBoundTranscludeFn = boundTranscludeFn;
6924         if (linkQueue) {
6925           linkQueue.push(scope);
6926           linkQueue.push(node);
6927           linkQueue.push(rootElement);
6928           linkQueue.push(childBoundTranscludeFn);
6929         } else {
6930           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6931             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6932           }
6933           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
6934         }
6935       };
6936     }
6937
6938
6939     /**
6940      * Sorting function for bound directives.
6941      */
6942     function byPriority(a, b) {
6943       var diff = b.priority - a.priority;
6944       if (diff !== 0) return diff;
6945       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6946       return a.index - b.index;
6947     }
6948
6949
6950     function assertNoDuplicate(what, previousDirective, directive, element) {
6951       if (previousDirective) {
6952         throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6953             previousDirective.name, directive.name, what, startingTag(element));
6954       }
6955     }
6956
6957
6958       function addTextInterpolateDirective(directives, text) {
6959         var interpolateFn = $interpolate(text, true);
6960         if (interpolateFn) {
6961           directives.push({
6962             priority: 0,
6963             compile: function textInterpolateCompileFn(templateNode) {
6964               // when transcluding a template that has bindings in the root
6965               // then we don't have a parent and should do this in the linkFn
6966               var parent = templateNode.parent(), hasCompileParent = parent.length;
6967               if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
6968
6969               return function textInterpolateLinkFn(scope, node) {
6970                 var parent = node.parent(),
6971                   bindings = parent.data('$binding') || [];
6972                 bindings.push(interpolateFn);
6973                 parent.data('$binding', bindings);
6974                 if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
6975                 scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6976                   node[0].nodeValue = value;
6977                 });
6978               };
6979             }
6980           });
6981         }
6982       }
6983
6984
6985     function getTrustedContext(node, attrNormalizedName) {
6986       if (attrNormalizedName == "srcdoc") {
6987         return $sce.HTML;
6988       }
6989       var tag = nodeName_(node);
6990       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6991       if (attrNormalizedName == "xlinkHref" ||
6992           (tag == "FORM" && attrNormalizedName == "action") ||
6993           (tag != "IMG" && (attrNormalizedName == "src" ||
6994                             attrNormalizedName == "ngSrc"))) {
6995         return $sce.RESOURCE_URL;
6996       }
6997     }
6998
6999
7000     function addAttrInterpolateDirective(node, directives, value, name) {
7001       var interpolateFn = $interpolate(value, true);
7002
7003       // no interpolation found -> ignore
7004       if (!interpolateFn) return;
7005
7006
7007       if (name === "multiple" && nodeName_(node) === "SELECT") {
7008         throw $compileMinErr("selmulti",
7009             "Binding to the 'multiple' attribute is not supported. Element: {0}",
7010             startingTag(node));
7011       }
7012
7013       directives.push({
7014         priority: 100,
7015         compile: function() {
7016             return {
7017               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
7018                 var $$observers = (attr.$$observers || (attr.$$observers = {}));
7019
7020                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
7021                   throw $compileMinErr('nodomevents',
7022                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
7023                           "ng- versions (such as ng-click instead of onclick) instead.");
7024                 }
7025
7026                 // we need to interpolate again, in case the attribute value has been updated
7027                 // (e.g. by another directive's compile function)
7028                 interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
7029
7030                 // if attribute was updated so that there is no interpolation going on we don't want to
7031                 // register any observers
7032                 if (!interpolateFn) return;
7033
7034                 // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
7035                 // actual attr value
7036                 attr[name] = interpolateFn(scope);
7037                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
7038                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
7039                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
7040                     //special case for class attribute addition + removal
7041                     //so that class changes can tap into the animation
7042                     //hooks provided by the $animate service. Be sure to
7043                     //skip animations when the first digest occurs (when
7044                     //both the new and the old values are the same) since
7045                     //the CSS classes are the non-interpolated values
7046                     if(name === 'class' && newValue != oldValue) {
7047                       attr.$updateClass(newValue, oldValue);
7048                     } else {
7049                       attr.$set(name, newValue);
7050                     }
7051                   });
7052               }
7053             };
7054           }
7055       });
7056     }
7057
7058
7059     /**
7060      * This is a special jqLite.replaceWith, which can replace items which
7061      * have no parents, provided that the containing jqLite collection is provided.
7062      *
7063      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
7064      *                               in the root of the tree.
7065      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
7066      *                                  the shell, but replace its DOM node reference.
7067      * @param {Node} newNode The new DOM node.
7068      */
7069     function replaceWith($rootElement, elementsToRemove, newNode) {
7070       var firstElementToRemove = elementsToRemove[0],
7071           removeCount = elementsToRemove.length,
7072           parent = firstElementToRemove.parentNode,
7073           i, ii;
7074
7075       if ($rootElement) {
7076         for(i = 0, ii = $rootElement.length; i < ii; i++) {
7077           if ($rootElement[i] == firstElementToRemove) {
7078             $rootElement[i++] = newNode;
7079             for (var j = i, j2 = j + removeCount - 1,
7080                      jj = $rootElement.length;
7081                  j < jj; j++, j2++) {
7082               if (j2 < jj) {
7083                 $rootElement[j] = $rootElement[j2];
7084               } else {
7085                 delete $rootElement[j];
7086               }
7087             }
7088             $rootElement.length -= removeCount - 1;
7089             break;
7090           }
7091         }
7092       }
7093
7094       if (parent) {
7095         parent.replaceChild(newNode, firstElementToRemove);
7096       }
7097       var fragment = document.createDocumentFragment();
7098       fragment.appendChild(firstElementToRemove);
7099       newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
7100       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
7101         var element = elementsToRemove[k];
7102         jqLite(element).remove(); // must do this way to clean up expando
7103         fragment.appendChild(element);
7104         delete elementsToRemove[k];
7105       }
7106
7107       elementsToRemove[0] = newNode;
7108       elementsToRemove.length = 1;
7109     }
7110
7111
7112     function cloneAndAnnotateFn(fn, annotation) {
7113       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
7114     }
7115   }];
7116 }
7117
7118 var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
7119 /**
7120  * Converts all accepted directives format into proper directive name.
7121  * All of these will become 'myDirective':
7122  *   my:Directive
7123  *   my-directive
7124  *   x-my-directive
7125  *   data-my:directive
7126  *
7127  * Also there is special case for Moz prefix starting with upper case letter.
7128  * @param name Name to normalize
7129  */
7130 function directiveNormalize(name) {
7131   return camelCase(name.replace(PREFIX_REGEXP, ''));
7132 }
7133
7134 /**
7135  * @ngdoc type
7136  * @name $compile.directive.Attributes
7137  *
7138  * @description
7139  * A shared object between directive compile / linking functions which contains normalized DOM
7140  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
7141  * needed since all of these are treated as equivalent in Angular:
7142  *
7143  * ```
7144  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7145  * ```
7146  */
7147
7148 /**
7149  * @ngdoc property
7150  * @name $compile.directive.Attributes#$attr
7151  *
7152  * @description
7153  * A map of DOM element attribute names to the normalized name. This is
7154  * needed to do reverse lookup from normalized name back to actual name.
7155  */
7156
7157
7158 /**
7159  * @ngdoc method
7160  * @name $compile.directive.Attributes#$set
7161  * @kind function
7162  *
7163  * @description
7164  * Set DOM element attribute value.
7165  *
7166  *
7167  * @param {string} name Normalized element attribute name of the property to modify. The name is
7168  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7169  *          property to the original name.
7170  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7171  */
7172
7173
7174
7175 /**
7176  * Closure compiler type information
7177  */
7178
7179 function nodesetLinkingFn(
7180   /* angular.Scope */ scope,
7181   /* NodeList */ nodeList,
7182   /* Element */ rootElement,
7183   /* function(Function) */ boundTranscludeFn
7184 ){}
7185
7186 function directiveLinkingFn(
7187   /* nodesetLinkingFn */ nodesetLinkingFn,
7188   /* angular.Scope */ scope,
7189   /* Node */ node,
7190   /* Element */ rootElement,
7191   /* function(Function) */ boundTranscludeFn
7192 ){}
7193
7194 function tokenDifference(str1, str2) {
7195   var values = '',
7196       tokens1 = str1.split(/\s+/),
7197       tokens2 = str2.split(/\s+/);
7198
7199   outer:
7200   for(var i = 0; i < tokens1.length; i++) {
7201     var token = tokens1[i];
7202     for(var j = 0; j < tokens2.length; j++) {
7203       if(token == tokens2[j]) continue outer;
7204     }
7205     values += (values.length > 0 ? ' ' : '') + token;
7206   }
7207   return values;
7208 }
7209
7210 /**
7211  * @ngdoc provider
7212  * @name $controllerProvider
7213  * @description
7214  * The {@link ng.$controller $controller service} is used by Angular to create new
7215  * controllers.
7216  *
7217  * This provider allows controller registration via the
7218  * {@link ng.$controllerProvider#register register} method.
7219  */
7220 function $ControllerProvider() {
7221   var controllers = {},
7222       CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7223
7224
7225   /**
7226    * @ngdoc method
7227    * @name $controllerProvider#register
7228    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7229    *    the names and the values are the constructors.
7230    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7231    *    annotations in the array notation).
7232    */
7233   this.register = function(name, constructor) {
7234     assertNotHasOwnProperty(name, 'controller');
7235     if (isObject(name)) {
7236       extend(controllers, name);
7237     } else {
7238       controllers[name] = constructor;
7239     }
7240   };
7241
7242
7243   this.$get = ['$injector', '$window', function($injector, $window) {
7244
7245     /**
7246      * @ngdoc service
7247      * @name $controller
7248      * @requires $injector
7249      *
7250      * @param {Function|string} constructor If called with a function then it's considered to be the
7251      *    controller constructor function. Otherwise it's considered to be a string which is used
7252      *    to retrieve the controller constructor using the following steps:
7253      *
7254      *    * check if a controller with given name is registered via `$controllerProvider`
7255      *    * check if evaluating the string on the current scope returns a constructor
7256      *    * check `window[constructor]` on the global `window` object
7257      *
7258      * @param {Object} locals Injection locals for Controller.
7259      * @return {Object} Instance of given controller.
7260      *
7261      * @description
7262      * `$controller` service is responsible for instantiating controllers.
7263      *
7264      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7265      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7266      */
7267     return function(expression, locals) {
7268       var instance, match, constructor, identifier;
7269
7270       if(isString(expression)) {
7271         match = expression.match(CNTRL_REG),
7272         constructor = match[1],
7273         identifier = match[3];
7274         expression = controllers.hasOwnProperty(constructor)
7275             ? controllers[constructor]
7276             : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7277
7278         assertArgFn(expression, constructor, true);
7279       }
7280
7281       instance = $injector.instantiate(expression, locals);
7282
7283       if (identifier) {
7284         if (!(locals && typeof locals.$scope === 'object')) {
7285           throw minErr('$controller')('noscp',
7286               "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7287               constructor || expression.name, identifier);
7288         }
7289
7290         locals.$scope[identifier] = instance;
7291       }
7292
7293       return instance;
7294     };
7295   }];
7296 }
7297
7298 /**
7299  * @ngdoc service
7300  * @name $document
7301  * @requires $window
7302  *
7303  * @description
7304  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7305  *
7306  * @example
7307    <example module="documentExample">
7308      <file name="index.html">
7309        <div ng-controller="ExampleController">
7310          <p>$document title: <b ng-bind="title"></b></p>
7311          <p>window.document title: <b ng-bind="windowTitle"></b></p>
7312        </div>
7313      </file>
7314      <file name="script.js">
7315        angular.module('documentExample', [])
7316          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
7317            $scope.title = $document[0].title;
7318            $scope.windowTitle = angular.element(window.document)[0].title;
7319          }]);
7320      </file>
7321    </example>
7322  */
7323 function $DocumentProvider(){
7324   this.$get = ['$window', function(window){
7325     return jqLite(window.document);
7326   }];
7327 }
7328
7329 /**
7330  * @ngdoc service
7331  * @name $exceptionHandler
7332  * @requires ng.$log
7333  *
7334  * @description
7335  * Any uncaught exception in angular expressions is delegated to this service.
7336  * The default implementation simply delegates to `$log.error` which logs it into
7337  * the browser console.
7338  *
7339  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7340  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7341  *
7342  * ## Example:
7343  *
7344  * ```js
7345  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7346  *     return function (exception, cause) {
7347  *       exception.message += ' (caused by "' + cause + '")';
7348  *       throw exception;
7349  *     };
7350  *   });
7351  * ```
7352  *
7353  * This example will override the normal action of `$exceptionHandler`, to make angular
7354  * exceptions fail hard when they happen, instead of just logging to the console.
7355  *
7356  * @param {Error} exception Exception associated with the error.
7357  * @param {string=} cause optional information about the context in which
7358  *       the error was thrown.
7359  *
7360  */
7361 function $ExceptionHandlerProvider() {
7362   this.$get = ['$log', function($log) {
7363     return function(exception, cause) {
7364       $log.error.apply($log, arguments);
7365     };
7366   }];
7367 }
7368
7369 /**
7370  * Parse headers into key value object
7371  *
7372  * @param {string} headers Raw headers as a string
7373  * @returns {Object} Parsed headers as key value object
7374  */
7375 function parseHeaders(headers) {
7376   var parsed = {}, key, val, i;
7377
7378   if (!headers) return parsed;
7379
7380   forEach(headers.split('\n'), function(line) {
7381     i = line.indexOf(':');
7382     key = lowercase(trim(line.substr(0, i)));
7383     val = trim(line.substr(i + 1));
7384
7385     if (key) {
7386       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
7387     }
7388   });
7389
7390   return parsed;
7391 }
7392
7393
7394 /**
7395  * Returns a function that provides access to parsed headers.
7396  *
7397  * Headers are lazy parsed when first requested.
7398  * @see parseHeaders
7399  *
7400  * @param {(string|Object)} headers Headers to provide access to.
7401  * @returns {function(string=)} Returns a getter function which if called with:
7402  *
7403  *   - if called with single an argument returns a single header value or null
7404  *   - if called with no arguments returns an object containing all headers.
7405  */
7406 function headersGetter(headers) {
7407   var headersObj = isObject(headers) ? headers : undefined;
7408
7409   return function(name) {
7410     if (!headersObj) headersObj =  parseHeaders(headers);
7411
7412     if (name) {
7413       return headersObj[lowercase(name)] || null;
7414     }
7415
7416     return headersObj;
7417   };
7418 }
7419
7420
7421 /**
7422  * Chain all given functions
7423  *
7424  * This function is used for both request and response transforming
7425  *
7426  * @param {*} data Data to transform.
7427  * @param {function(string=)} headers Http headers getter fn.
7428  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7429  * @returns {*} Transformed data.
7430  */
7431 function transformData(data, headers, fns) {
7432   if (isFunction(fns))
7433     return fns(data, headers);
7434
7435   forEach(fns, function(fn) {
7436     data = fn(data, headers);
7437   });
7438
7439   return data;
7440 }
7441
7442
7443 function isSuccess(status) {
7444   return 200 <= status && status < 300;
7445 }
7446
7447
7448 /**
7449  * @ngdoc provider
7450  * @name $httpProvider
7451  * @description
7452  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
7453  * */
7454 function $HttpProvider() {
7455   var JSON_START = /^\s*(\[|\{[^\{])/,
7456       JSON_END = /[\}\]]\s*$/,
7457       PROTECTION_PREFIX = /^\)\]\}',?\n/,
7458       CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7459
7460   /**
7461    * @ngdoc property
7462    * @name $httpProvider#defaults
7463    * @description
7464    *
7465    * Object containing default values for all {@link ng.$http $http} requests.
7466    *
7467    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
7468    * Defaults value is `'XSRF-TOKEN'`.
7469    *
7470    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
7471    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
7472    *
7473    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
7474    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
7475    * setting default headers.
7476    *     - **`defaults.headers.common`**
7477    *     - **`defaults.headers.post`**
7478    *     - **`defaults.headers.put`**
7479    *     - **`defaults.headers.patch`**
7480    **/
7481   var defaults = this.defaults = {
7482     // transform incoming response data
7483     transformResponse: [function(data) {
7484       if (isString(data)) {
7485         // strip json vulnerability protection prefix
7486         data = data.replace(PROTECTION_PREFIX, '');
7487         if (JSON_START.test(data) && JSON_END.test(data))
7488           data = fromJson(data);
7489       }
7490       return data;
7491     }],
7492
7493     // transform outgoing request data
7494     transformRequest: [function(d) {
7495       return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7496     }],
7497
7498     // default headers
7499     headers: {
7500       common: {
7501         'Accept': 'application/json, text/plain, */*'
7502       },
7503       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7504       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7505       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
7506     },
7507
7508     xsrfCookieName: 'XSRF-TOKEN',
7509     xsrfHeaderName: 'X-XSRF-TOKEN'
7510   };
7511
7512   /**
7513    * Are ordered by request, i.e. they are applied in the same order as the
7514    * array, on request, but reverse order, on response.
7515    */
7516   var interceptorFactories = this.interceptors = [];
7517
7518   /**
7519    * For historical reasons, response interceptors are ordered by the order in which
7520    * they are applied to the response. (This is the opposite of interceptorFactories)
7521    */
7522   var responseInterceptorFactories = this.responseInterceptors = [];
7523
7524   this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7525       function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7526
7527     var defaultCache = $cacheFactory('$http');
7528
7529     /**
7530      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7531      * The reversal is needed so that we can build up the interception chain around the
7532      * server request.
7533      */
7534     var reversedInterceptors = [];
7535
7536     forEach(interceptorFactories, function(interceptorFactory) {
7537       reversedInterceptors.unshift(isString(interceptorFactory)
7538           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7539     });
7540
7541     forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7542       var responseFn = isString(interceptorFactory)
7543           ? $injector.get(interceptorFactory)
7544           : $injector.invoke(interceptorFactory);
7545
7546       /**
7547        * Response interceptors go before "around" interceptors (no real reason, just
7548        * had to pick one.) But they are already reversed, so we can't use unshift, hence
7549        * the splice.
7550        */
7551       reversedInterceptors.splice(index, 0, {
7552         response: function(response) {
7553           return responseFn($q.when(response));
7554         },
7555         responseError: function(response) {
7556           return responseFn($q.reject(response));
7557         }
7558       });
7559     });
7560
7561
7562     /**
7563      * @ngdoc service
7564      * @kind function
7565      * @name $http
7566      * @requires ng.$httpBackend
7567      * @requires $cacheFactory
7568      * @requires $rootScope
7569      * @requires $q
7570      * @requires $injector
7571      *
7572      * @description
7573      * The `$http` service is a core Angular service that facilitates communication with the remote
7574      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7575      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7576      *
7577      * For unit testing applications that use `$http` service, see
7578      * {@link ngMock.$httpBackend $httpBackend mock}.
7579      *
7580      * For a higher level of abstraction, please check out the {@link ngResource.$resource
7581      * $resource} service.
7582      *
7583      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7584      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7585      * it is important to familiarize yourself with these APIs and the guarantees they provide.
7586      *
7587      *
7588      * # General usage
7589      * The `$http` service is a function which takes a single argument — a configuration object —
7590      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7591      * with two $http specific methods: `success` and `error`.
7592      *
7593      * ```js
7594      *   $http({method: 'GET', url: '/someUrl'}).
7595      *     success(function(data, status, headers, config) {
7596      *       // this callback will be called asynchronously
7597      *       // when the response is available
7598      *     }).
7599      *     error(function(data, status, headers, config) {
7600      *       // called asynchronously if an error occurs
7601      *       // or server returns response with an error status.
7602      *     });
7603      * ```
7604      *
7605      * Since the returned value of calling the $http function is a `promise`, you can also use
7606      * the `then` method to register callbacks, and these callbacks will receive a single argument –
7607      * an object representing the response. See the API signature and type info below for more
7608      * details.
7609      *
7610      * A response status code between 200 and 299 is considered a success status and
7611      * will result in the success callback being called. Note that if the response is a redirect,
7612      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7613      * called for such responses.
7614      *
7615      * # Writing Unit Tests that use $http
7616      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7617      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7618      * request using trained responses.
7619      *
7620      * ```
7621      * $httpBackend.expectGET(...);
7622      * $http.get(...);
7623      * $httpBackend.flush();
7624      * ```
7625      *
7626      * # Shortcut methods
7627      *
7628      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7629      * request data must be passed in for POST/PUT requests.
7630      *
7631      * ```js
7632      *   $http.get('/someUrl').success(successCallback);
7633      *   $http.post('/someUrl', data).success(successCallback);
7634      * ```
7635      *
7636      * Complete list of shortcut methods:
7637      *
7638      * - {@link ng.$http#get $http.get}
7639      * - {@link ng.$http#head $http.head}
7640      * - {@link ng.$http#post $http.post}
7641      * - {@link ng.$http#put $http.put}
7642      * - {@link ng.$http#delete $http.delete}
7643      * - {@link ng.$http#jsonp $http.jsonp}
7644      * - {@link ng.$http#patch $http.patch}
7645      *
7646      *
7647      * # Setting HTTP Headers
7648      *
7649      * The $http service will automatically add certain HTTP headers to all requests. These defaults
7650      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7651      * object, which currently contains this default configuration:
7652      *
7653      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7654      *   - `Accept: application/json, text/plain, * / *`
7655      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7656      *   - `Content-Type: application/json`
7657      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7658      *   - `Content-Type: application/json`
7659      *
7660      * To add or overwrite these defaults, simply add or remove a property from these configuration
7661      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7662      * with the lowercased HTTP method name as the key, e.g.
7663      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7664      *
7665      * The defaults can also be set at runtime via the `$http.defaults` object in the same
7666      * fashion. For example:
7667      *
7668      * ```
7669      * module.run(function($http) {
7670      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7671      * });
7672      * ```
7673      *
7674      * In addition, you can supply a `headers` property in the config object passed when
7675      * calling `$http(config)`, which overrides the defaults without changing them globally.
7676      *
7677      *
7678      * # Transforming Requests and Responses
7679      *
7680      * Both requests and responses can be transformed using transform functions. By default, Angular
7681      * applies these transformations:
7682      *
7683      * Request transformations:
7684      *
7685      * - If the `data` property of the request configuration object contains an object, serialize it
7686      *   into JSON format.
7687      *
7688      * Response transformations:
7689      *
7690      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7691      *  - If JSON response is detected, deserialize it using a JSON parser.
7692      *
7693      * To globally augment or override the default transforms, modify the
7694      * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7695      * properties. These properties are by default an array of transform functions, which allows you
7696      * to `push` or `unshift` a new transformation function into the transformation chain. You can
7697      * also decide to completely override any default transformations by assigning your
7698      * transformation functions to these properties directly without the array wrapper.  These defaults
7699      * are again available on the $http factory at run-time, which may be useful if you have run-time
7700      * services you wish to be involved in your transformations.
7701      *
7702      * Similarly, to locally override the request/response transforms, augment the
7703      * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7704      * into `$http`.
7705      *
7706      *
7707      * # Caching
7708      *
7709      * To enable caching, set the request configuration `cache` property to `true` (to use default
7710      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7711      * When the cache is enabled, `$http` stores the response from the server in the specified
7712      * cache. The next time the same request is made, the response is served from the cache without
7713      * sending a request to the server.
7714      *
7715      * Note that even if the response is served from cache, delivery of the data is asynchronous in
7716      * the same way that real requests are.
7717      *
7718      * If there are multiple GET requests for the same URL that should be cached using the same
7719      * cache, but the cache is not populated yet, only one request to the server will be made and
7720      * the remaining requests will be fulfilled using the response from the first request.
7721      *
7722      * You can change the default cache to a new object (built with
7723      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7724      * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7725      * their `cache` property to `true` will now use this cache object.
7726      *
7727      * If you set the default cache to `false` then only requests that specify their own custom
7728      * cache object will be cached.
7729      *
7730      * # Interceptors
7731      *
7732      * Before you start creating interceptors, be sure to understand the
7733      * {@link ng.$q $q and deferred/promise APIs}.
7734      *
7735      * For purposes of global error handling, authentication, or any kind of synchronous or
7736      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7737      * able to intercept requests before they are handed to the server and
7738      * responses before they are handed over to the application code that
7739      * initiated these requests. The interceptors leverage the {@link ng.$q
7740      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7741      *
7742      * The interceptors are service factories that are registered with the `$httpProvider` by
7743      * adding them to the `$httpProvider.interceptors` array. The factory is called and
7744      * injected with dependencies (if specified) and returns the interceptor.
7745      *
7746      * There are two kinds of interceptors (and two kinds of rejection interceptors):
7747      *
7748      *   * `request`: interceptors get called with a http `config` object. The function is free to
7749      *     modify the `config` object or create a new one. The function needs to return the `config`
7750      *     object directly, or a promise containing the `config` or a new `config` object.
7751      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7752      *     resolved with a rejection.
7753      *   * `response`: interceptors get called with http `response` object. The function is free to
7754      *     modify the `response` object or create a new one. The function needs to return the `response`
7755      *     object directly, or as a promise containing the `response` or a new `response` object.
7756      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7757      *     resolved with a rejection.
7758      *
7759      *
7760      * ```js
7761      *   // register the interceptor as a service
7762      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7763      *     return {
7764      *       // optional method
7765      *       'request': function(config) {
7766      *         // do something on success
7767      *         return config;
7768      *       },
7769      *
7770      *       // optional method
7771      *      'requestError': function(rejection) {
7772      *         // do something on error
7773      *         if (canRecover(rejection)) {
7774      *           return responseOrNewPromise
7775      *         }
7776      *         return $q.reject(rejection);
7777      *       },
7778      *
7779      *
7780      *
7781      *       // optional method
7782      *       'response': function(response) {
7783      *         // do something on success
7784      *         return response;
7785      *       },
7786      *
7787      *       // optional method
7788      *      'responseError': function(rejection) {
7789      *         // do something on error
7790      *         if (canRecover(rejection)) {
7791      *           return responseOrNewPromise
7792      *         }
7793      *         return $q.reject(rejection);
7794      *       }
7795      *     };
7796      *   });
7797      *
7798      *   $httpProvider.interceptors.push('myHttpInterceptor');
7799      *
7800      *
7801      *   // alternatively, register the interceptor via an anonymous factory
7802      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7803      *     return {
7804      *      'request': function(config) {
7805      *          // same as above
7806      *       },
7807      *
7808      *       'response': function(response) {
7809      *          // same as above
7810      *       }
7811      *     };
7812      *   });
7813      * ```
7814      *
7815      * # Response interceptors (DEPRECATED)
7816      *
7817      * Before you start creating interceptors, be sure to understand the
7818      * {@link ng.$q $q and deferred/promise APIs}.
7819      *
7820      * For purposes of global error handling, authentication or any kind of synchronous or
7821      * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7822      * responses for http requests before they are handed over to the application code that
7823      * initiated these requests. The response interceptors leverage the {@link ng.$q
7824      * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7825      *
7826      * The interceptors are service factories that are registered with the $httpProvider by
7827      * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7828      * injected with dependencies (if specified) and returns the interceptor  — a function that
7829      * takes a {@link ng.$q promise} and returns the original or a new promise.
7830      *
7831      * ```js
7832      *   // register the interceptor as a service
7833      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7834      *     return function(promise) {
7835      *       return promise.then(function(response) {
7836      *         // do something on success
7837      *         return response;
7838      *       }, function(response) {
7839      *         // do something on error
7840      *         if (canRecover(response)) {
7841      *           return responseOrNewPromise
7842      *         }
7843      *         return $q.reject(response);
7844      *       });
7845      *     }
7846      *   });
7847      *
7848      *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7849      *
7850      *
7851      *   // register the interceptor via an anonymous factory
7852      *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7853      *     return function(promise) {
7854      *       // same as above
7855      *     }
7856      *   });
7857      * ```
7858      *
7859      *
7860      * # Security Considerations
7861      *
7862      * When designing web applications, consider security threats from:
7863      *
7864      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7865      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7866      *
7867      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7868      * pre-configured with strategies that address these issues, but for this to work backend server
7869      * cooperation is required.
7870      *
7871      * ## JSON Vulnerability Protection
7872      *
7873      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7874      * allows third party website to turn your JSON resource URL into
7875      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7876      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
7877      * Angular will automatically strip the prefix before processing it as JSON.
7878      *
7879      * For example if your server needs to return:
7880      * ```js
7881      * ['one','two']
7882      * ```
7883      *
7884      * which is vulnerable to attack, your server can return:
7885      * ```js
7886      * )]}',
7887      * ['one','two']
7888      * ```
7889      *
7890      * Angular will strip the prefix, before processing the JSON.
7891      *
7892      *
7893      * ## Cross Site Request Forgery (XSRF) Protection
7894      *
7895      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7896      * an unauthorized site can gain your user's private data. Angular provides a mechanism
7897      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7898      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7899      * JavaScript that runs on your domain could read the cookie, your server can be assured that
7900      * the XHR came from JavaScript running on your domain. The header will not be set for
7901      * cross-domain requests.
7902      *
7903      * To take advantage of this, your server needs to set a token in a JavaScript readable session
7904      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7905      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7906      * that only JavaScript running on your domain could have sent the request. The token must be
7907      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7908      * making up its own tokens). We recommend that the token is a digest of your site's
7909      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
7910      * for added security.
7911      *
7912      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7913      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7914      * or the per-request config object.
7915      *
7916      *
7917      * @param {object} config Object describing the request to be made and how it should be
7918      *    processed. The object has following properties:
7919      *
7920      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7921      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7922      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7923      *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7924      *      JSONified.
7925      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7926      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7927      *      HTTP headers to send to the server. If the return value of a function is null, the
7928      *      header will not be sent.
7929      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7930      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7931      *    - **transformRequest** –
7932      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7933      *      transform function or an array of such functions. The transform function takes the http
7934      *      request body and headers and returns its transformed (typically serialized) version.
7935      *    - **transformResponse** –
7936      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7937      *      transform function or an array of such functions. The transform function takes the http
7938      *      response body and headers and returns its transformed (typically deserialized) version.
7939      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7940      *      GET request, otherwise if a cache instance built with
7941      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7942      *      caching.
7943      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7944      *      that should abort the request when resolved.
7945      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
7946      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
7947      *      for more information.
7948      *    - **responseType** - `{string}` - see
7949      *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
7950      *
7951      * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7952      *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7953      *   method takes two arguments a success and an error callback which will be called with a
7954      *   response object. The `success` and `error` methods take a single argument - a function that
7955      *   will be called when the request succeeds or fails respectively. The arguments passed into
7956      *   these functions are destructured representation of the response object passed into the
7957      *   `then` method. The response object has these properties:
7958      *
7959      *   - **data** – `{string|Object}` – The response body transformed with the transform
7960      *     functions.
7961      *   - **status** – `{number}` – HTTP status code of the response.
7962      *   - **headers** – `{function([headerName])}` – Header getter function.
7963      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7964      *   - **statusText** – `{string}` – HTTP status text of the response.
7965      *
7966      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7967      *   requests. This is primarily meant to be used for debugging purposes.
7968      *
7969      *
7970      * @example
7971 <example module="httpExample">
7972 <file name="index.html">
7973   <div ng-controller="FetchController">
7974     <select ng-model="method">
7975       <option>GET</option>
7976       <option>JSONP</option>
7977     </select>
7978     <input type="text" ng-model="url" size="80"/>
7979     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7980     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7981     <button id="samplejsonpbtn"
7982       ng-click="updateModel('JSONP',
7983                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7984       Sample JSONP
7985     </button>
7986     <button id="invalidjsonpbtn"
7987       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7988         Invalid JSONP
7989       </button>
7990     <pre>http status code: {{status}}</pre>
7991     <pre>http response data: {{data}}</pre>
7992   </div>
7993 </file>
7994 <file name="script.js">
7995   angular.module('httpExample', [])
7996     .controller('FetchController', ['$scope', '$http', '$templateCache',
7997       function($scope, $http, $templateCache) {
7998         $scope.method = 'GET';
7999         $scope.url = 'http-hello.html';
8000
8001         $scope.fetch = function() {
8002           $scope.code = null;
8003           $scope.response = null;
8004
8005           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
8006             success(function(data, status) {
8007               $scope.status = status;
8008               $scope.data = data;
8009             }).
8010             error(function(data, status) {
8011               $scope.data = data || "Request failed";
8012               $scope.status = status;
8013           });
8014         };
8015
8016         $scope.updateModel = function(method, url) {
8017           $scope.method = method;
8018           $scope.url = url;
8019         };
8020       }]);
8021 </file>
8022 <file name="http-hello.html">
8023   Hello, $http!
8024 </file>
8025 <file name="protractor.js" type="protractor">
8026   var status = element(by.binding('status'));
8027   var data = element(by.binding('data'));
8028   var fetchBtn = element(by.id('fetchbtn'));
8029   var sampleGetBtn = element(by.id('samplegetbtn'));
8030   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
8031   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
8032
8033   it('should make an xhr GET request', function() {
8034     sampleGetBtn.click();
8035     fetchBtn.click();
8036     expect(status.getText()).toMatch('200');
8037     expect(data.getText()).toMatch(/Hello, \$http!/);
8038   });
8039
8040   it('should make a JSONP request to angularjs.org', function() {
8041     sampleJsonpBtn.click();
8042     fetchBtn.click();
8043     expect(status.getText()).toMatch('200');
8044     expect(data.getText()).toMatch(/Super Hero!/);
8045   });
8046
8047   it('should make JSONP request to invalid URL and invoke the error handler',
8048       function() {
8049     invalidJsonpBtn.click();
8050     fetchBtn.click();
8051     expect(status.getText()).toMatch('0');
8052     expect(data.getText()).toMatch('Request failed');
8053   });
8054 </file>
8055 </example>
8056      */
8057     function $http(requestConfig) {
8058       var config = {
8059         method: 'get',
8060         transformRequest: defaults.transformRequest,
8061         transformResponse: defaults.transformResponse
8062       };
8063       var headers = mergeHeaders(requestConfig);
8064
8065       extend(config, requestConfig);
8066       config.headers = headers;
8067       config.method = uppercase(config.method);
8068
8069       var serverRequest = function(config) {
8070         headers = config.headers;
8071         var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
8072
8073         // strip content-type if data is undefined
8074         if (isUndefined(reqData)) {
8075           forEach(headers, function(value, header) {
8076             if (lowercase(header) === 'content-type') {
8077                 delete headers[header];
8078             }
8079           });
8080         }
8081
8082         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
8083           config.withCredentials = defaults.withCredentials;
8084         }
8085
8086         // send request
8087         return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
8088       };
8089
8090       var chain = [serverRequest, undefined];
8091       var promise = $q.when(config);
8092
8093       // apply interceptors
8094       forEach(reversedInterceptors, function(interceptor) {
8095         if (interceptor.request || interceptor.requestError) {
8096           chain.unshift(interceptor.request, interceptor.requestError);
8097         }
8098         if (interceptor.response || interceptor.responseError) {
8099           chain.push(interceptor.response, interceptor.responseError);
8100         }
8101       });
8102
8103       while(chain.length) {
8104         var thenFn = chain.shift();
8105         var rejectFn = chain.shift();
8106
8107         promise = promise.then(thenFn, rejectFn);
8108       }
8109
8110       promise.success = function(fn) {
8111         promise.then(function(response) {
8112           fn(response.data, response.status, response.headers, config);
8113         });
8114         return promise;
8115       };
8116
8117       promise.error = function(fn) {
8118         promise.then(null, function(response) {
8119           fn(response.data, response.status, response.headers, config);
8120         });
8121         return promise;
8122       };
8123
8124       return promise;
8125
8126       function transformResponse(response) {
8127         // make a copy since the response must be cacheable
8128         var resp = extend({}, response, {
8129           data: transformData(response.data, response.headers, config.transformResponse)
8130         });
8131         return (isSuccess(response.status))
8132           ? resp
8133           : $q.reject(resp);
8134       }
8135
8136       function mergeHeaders(config) {
8137         var defHeaders = defaults.headers,
8138             reqHeaders = extend({}, config.headers),
8139             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
8140
8141         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
8142
8143         // using for-in instead of forEach to avoid unecessary iteration after header has been found
8144         defaultHeadersIteration:
8145         for (defHeaderName in defHeaders) {
8146           lowercaseDefHeaderName = lowercase(defHeaderName);
8147
8148           for (reqHeaderName in reqHeaders) {
8149             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
8150               continue defaultHeadersIteration;
8151             }
8152           }
8153
8154           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
8155         }
8156
8157         // execute if header value is a function for merged headers
8158         execHeaders(reqHeaders);
8159         return reqHeaders;
8160
8161         function execHeaders(headers) {
8162           var headerContent;
8163
8164           forEach(headers, function(headerFn, header) {
8165             if (isFunction(headerFn)) {
8166               headerContent = headerFn();
8167               if (headerContent != null) {
8168                 headers[header] = headerContent;
8169               } else {
8170                 delete headers[header];
8171               }
8172             }
8173           });
8174         }
8175       }
8176     }
8177
8178     $http.pendingRequests = [];
8179
8180     /**
8181      * @ngdoc method
8182      * @name $http#get
8183      *
8184      * @description
8185      * Shortcut method to perform `GET` request.
8186      *
8187      * @param {string} url Relative or absolute URL specifying the destination of the request
8188      * @param {Object=} config Optional configuration object
8189      * @returns {HttpPromise} Future object
8190      */
8191
8192     /**
8193      * @ngdoc method
8194      * @name $http#delete
8195      *
8196      * @description
8197      * Shortcut method to perform `DELETE` request.
8198      *
8199      * @param {string} url Relative or absolute URL specifying the destination of the request
8200      * @param {Object=} config Optional configuration object
8201      * @returns {HttpPromise} Future object
8202      */
8203
8204     /**
8205      * @ngdoc method
8206      * @name $http#head
8207      *
8208      * @description
8209      * Shortcut method to perform `HEAD` request.
8210      *
8211      * @param {string} url Relative or absolute URL specifying the destination of the request
8212      * @param {Object=} config Optional configuration object
8213      * @returns {HttpPromise} Future object
8214      */
8215
8216     /**
8217      * @ngdoc method
8218      * @name $http#jsonp
8219      *
8220      * @description
8221      * Shortcut method to perform `JSONP` request.
8222      *
8223      * @param {string} url Relative or absolute URL specifying the destination of the request.
8224      *                     The name of the callback should be the string `JSON_CALLBACK`.
8225      * @param {Object=} config Optional configuration object
8226      * @returns {HttpPromise} Future object
8227      */
8228     createShortMethods('get', 'delete', 'head', 'jsonp');
8229
8230     /**
8231      * @ngdoc method
8232      * @name $http#post
8233      *
8234      * @description
8235      * Shortcut method to perform `POST` request.
8236      *
8237      * @param {string} url Relative or absolute URL specifying the destination of the request
8238      * @param {*} data Request content
8239      * @param {Object=} config Optional configuration object
8240      * @returns {HttpPromise} Future object
8241      */
8242
8243     /**
8244      * @ngdoc method
8245      * @name $http#put
8246      *
8247      * @description
8248      * Shortcut method to perform `PUT` request.
8249      *
8250      * @param {string} url Relative or absolute URL specifying the destination of the request
8251      * @param {*} data Request content
8252      * @param {Object=} config Optional configuration object
8253      * @returns {HttpPromise} Future object
8254      */
8255     createShortMethodsWithData('post', 'put');
8256
8257         /**
8258          * @ngdoc property
8259          * @name $http#defaults
8260          *
8261          * @description
8262          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8263          * default headers, withCredentials as well as request and response transformations.
8264          *
8265          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8266          */
8267     $http.defaults = defaults;
8268
8269
8270     return $http;
8271
8272
8273     function createShortMethods(names) {
8274       forEach(arguments, function(name) {
8275         $http[name] = function(url, config) {
8276           return $http(extend(config || {}, {
8277             method: name,
8278             url: url
8279           }));
8280         };
8281       });
8282     }
8283
8284
8285     function createShortMethodsWithData(name) {
8286       forEach(arguments, function(name) {
8287         $http[name] = function(url, data, config) {
8288           return $http(extend(config || {}, {
8289             method: name,
8290             url: url,
8291             data: data
8292           }));
8293         };
8294       });
8295     }
8296
8297
8298     /**
8299      * Makes the request.
8300      *
8301      * !!! ACCESSES CLOSURE VARS:
8302      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8303      */
8304     function sendReq(config, reqData, reqHeaders) {
8305       var deferred = $q.defer(),
8306           promise = deferred.promise,
8307           cache,
8308           cachedResp,
8309           url = buildUrl(config.url, config.params);
8310
8311       $http.pendingRequests.push(config);
8312       promise.then(removePendingReq, removePendingReq);
8313
8314
8315       if ((config.cache || defaults.cache) && config.cache !== false &&
8316           (config.method === 'GET' || config.method === 'JSONP')) {
8317         cache = isObject(config.cache) ? config.cache
8318               : isObject(defaults.cache) ? defaults.cache
8319               : defaultCache;
8320       }
8321
8322       if (cache) {
8323         cachedResp = cache.get(url);
8324         if (isDefined(cachedResp)) {
8325           if (isPromiseLike(cachedResp)) {
8326             // cached request has already been sent, but there is no response yet
8327             cachedResp.then(removePendingReq, removePendingReq);
8328             return cachedResp;
8329           } else {
8330             // serving from cache
8331             if (isArray(cachedResp)) {
8332               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
8333             } else {
8334               resolvePromise(cachedResp, 200, {}, 'OK');
8335             }
8336           }
8337         } else {
8338           // put the promise for the non-transformed response into cache as a placeholder
8339           cache.put(url, promise);
8340         }
8341       }
8342
8343
8344       // if we won't have the response in cache, set the xsrf headers and
8345       // send the request to the backend
8346       if (isUndefined(cachedResp)) {
8347         var xsrfValue = urlIsSameOrigin(config.url)
8348             ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
8349             : undefined;
8350         if (xsrfValue) {
8351           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
8352         }
8353
8354         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8355             config.withCredentials, config.responseType);
8356       }
8357
8358       return promise;
8359
8360
8361       /**
8362        * Callback registered to $httpBackend():
8363        *  - caches the response if desired
8364        *  - resolves the raw $http promise
8365        *  - calls $apply
8366        */
8367       function done(status, response, headersString, statusText) {
8368         if (cache) {
8369           if (isSuccess(status)) {
8370             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8371           } else {
8372             // remove promise from the cache
8373             cache.remove(url);
8374           }
8375         }
8376
8377         resolvePromise(response, status, headersString, statusText);
8378         if (!$rootScope.$$phase) $rootScope.$apply();
8379       }
8380
8381
8382       /**
8383        * Resolves the raw $http promise.
8384        */
8385       function resolvePromise(response, status, headers, statusText) {
8386         // normalize internal statuses to 0
8387         status = Math.max(status, 0);
8388
8389         (isSuccess(status) ? deferred.resolve : deferred.reject)({
8390           data: response,
8391           status: status,
8392           headers: headersGetter(headers),
8393           config: config,
8394           statusText : statusText
8395         });
8396       }
8397
8398
8399       function removePendingReq() {
8400         var idx = indexOf($http.pendingRequests, config);
8401         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8402       }
8403     }
8404
8405
8406     function buildUrl(url, params) {
8407       if (!params) return url;
8408       var parts = [];
8409       forEachSorted(params, function(value, key) {
8410         if (value === null || isUndefined(value)) return;
8411         if (!isArray(value)) value = [value];
8412
8413         forEach(value, function(v) {
8414           if (isObject(v)) {
8415             if (isDate(v)){
8416               v = v.toISOString();
8417             } else {
8418               v = toJson(v);
8419             }
8420           }
8421           parts.push(encodeUriQuery(key) + '=' +
8422                      encodeUriQuery(v));
8423         });
8424       });
8425       if(parts.length > 0) {
8426         url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8427       }
8428       return url;
8429     }
8430   }];
8431 }
8432
8433 function createXhr(method) {
8434     //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8435     //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8436     //if it is available
8437     if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
8438       !window.XMLHttpRequest)) {
8439       return new window.ActiveXObject("Microsoft.XMLHTTP");
8440     } else if (window.XMLHttpRequest) {
8441       return new window.XMLHttpRequest();
8442     }
8443
8444     throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8445 }
8446
8447 /**
8448  * @ngdoc service
8449  * @name $httpBackend
8450  * @requires $window
8451  * @requires $document
8452  *
8453  * @description
8454  * HTTP backend used by the {@link ng.$http service} that delegates to
8455  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8456  *
8457  * You should never need to use this service directly, instead use the higher-level abstractions:
8458  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8459  *
8460  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8461  * $httpBackend} which can be trained with responses.
8462  */
8463 function $HttpBackendProvider() {
8464   this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
8465     return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8466   }];
8467 }
8468
8469 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8470   var ABORTED = -1;
8471
8472   // TODO(vojta): fix the signature
8473   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8474     var status;
8475     $browser.$$incOutstandingRequestCount();
8476     url = url || $browser.url();
8477
8478     if (lowercase(method) == 'jsonp') {
8479       var callbackId = '_' + (callbacks.counter++).toString(36);
8480       callbacks[callbackId] = function(data) {
8481         callbacks[callbackId].data = data;
8482         callbacks[callbackId].called = true;
8483       };
8484
8485       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8486           callbackId, function(status, text) {
8487         completeRequest(callback, status, callbacks[callbackId].data, "", text);
8488         callbacks[callbackId] = noop;
8489       });
8490     } else {
8491
8492       var xhr = createXhr(method);
8493
8494       xhr.open(method, url, true);
8495       forEach(headers, function(value, key) {
8496         if (isDefined(value)) {
8497             xhr.setRequestHeader(key, value);
8498         }
8499       });
8500
8501       // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8502       // response is in the cache. the promise api will ensure that to the app code the api is
8503       // always async
8504       xhr.onreadystatechange = function() {
8505         // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8506         // xhrs that are resolved while the app is in the background (see #5426).
8507         // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8508         // continuing
8509         //
8510         // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8511         // Safari respectively.
8512         if (xhr && xhr.readyState == 4) {
8513           var responseHeaders = null,
8514               response = null,
8515               statusText = '';
8516
8517           if(status !== ABORTED) {
8518             responseHeaders = xhr.getAllResponseHeaders();
8519
8520             // responseText is the old-school way of retrieving response (supported by IE8 & 9)
8521             // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8522             response = ('response' in xhr) ? xhr.response : xhr.responseText;
8523           }
8524
8525           // Accessing statusText on an aborted xhr object will
8526           // throw an 'c00c023f error' in IE9 and lower, don't touch it.
8527           if (!(status === ABORTED && msie < 10)) {
8528             statusText = xhr.statusText;
8529           }
8530
8531           completeRequest(callback,
8532               status || xhr.status,
8533               response,
8534               responseHeaders,
8535               statusText);
8536         }
8537       };
8538
8539       if (withCredentials) {
8540         xhr.withCredentials = true;
8541       }
8542
8543       if (responseType) {
8544         try {
8545           xhr.responseType = responseType;
8546         } catch (e) {
8547           // WebKit added support for the json responseType value on 09/03/2013
8548           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8549           // known to throw when setting the value "json" as the response type. Other older
8550           // browsers implementing the responseType
8551           //
8552           // The json response type can be ignored if not supported, because JSON payloads are
8553           // parsed on the client-side regardless.
8554           if (responseType !== 'json') {
8555             throw e;
8556           }
8557         }
8558       }
8559
8560       xhr.send(post || null);
8561     }
8562
8563     if (timeout > 0) {
8564       var timeoutId = $browserDefer(timeoutRequest, timeout);
8565     } else if (isPromiseLike(timeout)) {
8566       timeout.then(timeoutRequest);
8567     }
8568
8569
8570     function timeoutRequest() {
8571       status = ABORTED;
8572       jsonpDone && jsonpDone();
8573       xhr && xhr.abort();
8574     }
8575
8576     function completeRequest(callback, status, response, headersString, statusText) {
8577       // cancel timeout and subsequent timeout promise resolution
8578       timeoutId && $browserDefer.cancel(timeoutId);
8579       jsonpDone = xhr = null;
8580
8581       // fix status code when it is 0 (0 status is undocumented).
8582       // Occurs when accessing file resources or on Android 4.1 stock browser
8583       // while retrieving files from application cache.
8584       if (status === 0) {
8585         status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8586       }
8587
8588       // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8589       status = status === 1223 ? 204 : status;
8590       statusText = statusText || '';
8591
8592       callback(status, response, headersString, statusText);
8593       $browser.$$completeOutstandingRequest(noop);
8594     }
8595   };
8596
8597   function jsonpReq(url, callbackId, done) {
8598     // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8599     // - fetches local scripts via XHR and evals them
8600     // - adds and immediately removes script elements from the document
8601     var script = rawDocument.createElement('script'), callback = null;
8602     script.type = "text/javascript";
8603     script.src = url;
8604     script.async = true;
8605
8606     callback = function(event) {
8607       removeEventListenerFn(script, "load", callback);
8608       removeEventListenerFn(script, "error", callback);
8609       rawDocument.body.removeChild(script);
8610       script = null;
8611       var status = -1;
8612       var text = "unknown";
8613
8614       if (event) {
8615         if (event.type === "load" && !callbacks[callbackId].called) {
8616           event = { type: "error" };
8617         }
8618         text = event.type;
8619         status = event.type === "error" ? 404 : 200;
8620       }
8621
8622       if (done) {
8623         done(status, text);
8624       }
8625     };
8626
8627     addEventListenerFn(script, "load", callback);
8628     addEventListenerFn(script, "error", callback);
8629
8630     if (msie <= 8) {
8631       script.onreadystatechange = function() {
8632         if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
8633           script.onreadystatechange = null;
8634           callback({
8635             type: 'load'
8636           });
8637         }
8638       };
8639     }
8640
8641     rawDocument.body.appendChild(script);
8642     return callback;
8643   }
8644 }
8645
8646 var $interpolateMinErr = minErr('$interpolate');
8647
8648 /**
8649  * @ngdoc provider
8650  * @name $interpolateProvider
8651  * @kind function
8652  *
8653  * @description
8654  *
8655  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8656  *
8657  * @example
8658 <example module="customInterpolationApp">
8659 <file name="index.html">
8660 <script>
8661   var customInterpolationApp = angular.module('customInterpolationApp', []);
8662
8663   customInterpolationApp.config(function($interpolateProvider) {
8664     $interpolateProvider.startSymbol('//');
8665     $interpolateProvider.endSymbol('//');
8666   });
8667
8668
8669   customInterpolationApp.controller('DemoController', function() {
8670       this.label = "This binding is brought you by // interpolation symbols.";
8671   });
8672 </script>
8673 <div ng-app="App" ng-controller="DemoController as demo">
8674     //demo.label//
8675 </div>
8676 </file>
8677 <file name="protractor.js" type="protractor">
8678   it('should interpolate binding with custom symbols', function() {
8679     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8680   });
8681 </file>
8682 </example>
8683  */
8684 function $InterpolateProvider() {
8685   var startSymbol = '{{';
8686   var endSymbol = '}}';
8687
8688   /**
8689    * @ngdoc method
8690    * @name $interpolateProvider#startSymbol
8691    * @description
8692    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8693    *
8694    * @param {string=} value new value to set the starting symbol to.
8695    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8696    */
8697   this.startSymbol = function(value){
8698     if (value) {
8699       startSymbol = value;
8700       return this;
8701     } else {
8702       return startSymbol;
8703     }
8704   };
8705
8706   /**
8707    * @ngdoc method
8708    * @name $interpolateProvider#endSymbol
8709    * @description
8710    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8711    *
8712    * @param {string=} value new value to set the ending symbol to.
8713    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8714    */
8715   this.endSymbol = function(value){
8716     if (value) {
8717       endSymbol = value;
8718       return this;
8719     } else {
8720       return endSymbol;
8721     }
8722   };
8723
8724
8725   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8726     var startSymbolLength = startSymbol.length,
8727         endSymbolLength = endSymbol.length;
8728
8729     /**
8730      * @ngdoc service
8731      * @name $interpolate
8732      * @kind function
8733      *
8734      * @requires $parse
8735      * @requires $sce
8736      *
8737      * @description
8738      *
8739      * Compiles a string with markup into an interpolation function. This service is used by the
8740      * HTML {@link ng.$compile $compile} service for data binding. See
8741      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8742      * interpolation markup.
8743      *
8744      *
8745      * ```js
8746      *   var $interpolate = ...; // injected
8747      *   var exp = $interpolate('Hello {{name | uppercase}}!');
8748      *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8749      * ```
8750      *
8751      *
8752      * @param {string} text The text with markup to interpolate.
8753      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8754      *    embedded expression in order to return an interpolation function. Strings with no
8755      *    embedded expression will return null for the interpolation function.
8756      * @param {string=} trustedContext when provided, the returned function passes the interpolated
8757      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8758      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8759      *    provides Strict Contextual Escaping for details.
8760      * @returns {function(context)} an interpolation function which is used to compute the
8761      *    interpolated string. The function has these parameters:
8762      *
8763      *    * `context`: an object against which any expressions embedded in the strings are evaluated
8764      *      against.
8765      *
8766      */
8767     function $interpolate(text, mustHaveExpression, trustedContext) {
8768       var startIndex,
8769           endIndex,
8770           index = 0,
8771           parts = [],
8772           length = text.length,
8773           hasInterpolation = false,
8774           fn,
8775           exp,
8776           concat = [];
8777
8778       while(index < length) {
8779         if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8780              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8781           (index != startIndex) && parts.push(text.substring(index, startIndex));
8782           parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8783           fn.exp = exp;
8784           index = endIndex + endSymbolLength;
8785           hasInterpolation = true;
8786         } else {
8787           // we did not find anything, so we have to add the remainder to the parts array
8788           (index != length) && parts.push(text.substring(index));
8789           index = length;
8790         }
8791       }
8792
8793       if (!(length = parts.length)) {
8794         // we added, nothing, must have been an empty string.
8795         parts.push('');
8796         length = 1;
8797       }
8798
8799       // Concatenating expressions makes it hard to reason about whether some combination of
8800       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8801       // single expression be used for iframe[src], object[src], etc., we ensure that the value
8802       // that's used is assigned or constructed by some JS code somewhere that is more testable or
8803       // make it obvious that you bound the value to some user controlled value.  This helps reduce
8804       // the load when auditing for XSS issues.
8805       if (trustedContext && parts.length > 1) {
8806           throw $interpolateMinErr('noconcat',
8807               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8808               "interpolations that concatenate multiple expressions when a trusted value is " +
8809               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8810       }
8811
8812       if (!mustHaveExpression  || hasInterpolation) {
8813         concat.length = length;
8814         fn = function(context) {
8815           try {
8816             for(var i = 0, ii = length, part; i<ii; i++) {
8817               if (typeof (part = parts[i]) == 'function') {
8818                 part = part(context);
8819                 if (trustedContext) {
8820                   part = $sce.getTrusted(trustedContext, part);
8821                 } else {
8822                   part = $sce.valueOf(part);
8823                 }
8824                 if (part == null) { // null || undefined
8825                   part = '';
8826                 } else {
8827                   switch (typeof part) {
8828                     case 'string':
8829                     {
8830                       break;
8831                     }
8832                     case 'number':
8833                     {
8834                       part = '' + part;
8835                       break;
8836                     }
8837                     default:
8838                     {
8839                       part = toJson(part);
8840                     }
8841                   }
8842                 }
8843               }
8844               concat[i] = part;
8845             }
8846             return concat.join('');
8847           }
8848           catch(err) {
8849             var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8850                 err.toString());
8851             $exceptionHandler(newErr);
8852           }
8853         };
8854         fn.exp = text;
8855         fn.parts = parts;
8856         return fn;
8857       }
8858     }
8859
8860
8861     /**
8862      * @ngdoc method
8863      * @name $interpolate#startSymbol
8864      * @description
8865      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8866      *
8867      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
8868      * the symbol.
8869      *
8870      * @returns {string} start symbol.
8871      */
8872     $interpolate.startSymbol = function() {
8873       return startSymbol;
8874     };
8875
8876
8877     /**
8878      * @ngdoc method
8879      * @name $interpolate#endSymbol
8880      * @description
8881      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8882      *
8883      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
8884      * the symbol.
8885      *
8886      * @returns {string} end symbol.
8887      */
8888     $interpolate.endSymbol = function() {
8889       return endSymbol;
8890     };
8891
8892     return $interpolate;
8893   }];
8894 }
8895
8896 function $IntervalProvider() {
8897   this.$get = ['$rootScope', '$window', '$q',
8898        function($rootScope,   $window,   $q) {
8899     var intervals = {};
8900
8901
8902      /**
8903       * @ngdoc service
8904       * @name $interval
8905       *
8906       * @description
8907       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8908       * milliseconds.
8909       *
8910       * The return value of registering an interval function is a promise. This promise will be
8911       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8912       * run indefinitely if `count` is not defined. The value of the notification will be the
8913       * number of iterations that have run.
8914       * To cancel an interval, call `$interval.cancel(promise)`.
8915       *
8916       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
8917       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8918       * time.
8919       *
8920       * <div class="alert alert-warning">
8921       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8922       * with them.  In particular they are not automatically destroyed when a controller's scope or a
8923       * directive's element are destroyed.
8924       * You should take this into consideration and make sure to always cancel the interval at the
8925       * appropriate moment.  See the example below for more details on how and when to do this.
8926       * </div>
8927       *
8928       * @param {function()} fn A function that should be called repeatedly.
8929       * @param {number} delay Number of milliseconds between each function call.
8930       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8931       *   indefinitely.
8932       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8933       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
8934       * @returns {promise} A promise which will be notified on each iteration.
8935       *
8936       * @example
8937       * <example module="intervalExample">
8938       * <file name="index.html">
8939       *   <script>
8940       *     angular.module('intervalExample', [])
8941       *       .controller('ExampleController', ['$scope', '$interval',
8942       *         function($scope, $interval) {
8943       *           $scope.format = 'M/d/yy h:mm:ss a';
8944       *           $scope.blood_1 = 100;
8945       *           $scope.blood_2 = 120;
8946       *
8947       *           var stop;
8948       *           $scope.fight = function() {
8949       *             // Don't start a new fight if we are already fighting
8950       *             if ( angular.isDefined(stop) ) return;
8951       *
8952       *           stop = $interval(function() {
8953       *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8954       *               $scope.blood_1 = $scope.blood_1 - 3;
8955       *               $scope.blood_2 = $scope.blood_2 - 4;
8956       *             } else {
8957       *               $scope.stopFight();
8958       *             }
8959       *           }, 100);
8960       *         };
8961       *
8962       *         $scope.stopFight = function() {
8963       *           if (angular.isDefined(stop)) {
8964       *             $interval.cancel(stop);
8965       *             stop = undefined;
8966       *           }
8967       *         };
8968       *
8969       *         $scope.resetFight = function() {
8970       *           $scope.blood_1 = 100;
8971       *           $scope.blood_2 = 120;
8972       *         };
8973       *
8974       *         $scope.$on('$destroy', function() {
8975       *           // Make sure that the interval is destroyed too
8976       *           $scope.stopFight();
8977       *         });
8978       *       }])
8979       *       // Register the 'myCurrentTime' directive factory method.
8980       *       // We inject $interval and dateFilter service since the factory method is DI.
8981       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
8982       *         function($interval, dateFilter) {
8983       *           // return the directive link function. (compile function not needed)
8984       *           return function(scope, element, attrs) {
8985       *             var format,  // date format
8986       *                 stopTime; // so that we can cancel the time updates
8987       *
8988       *             // used to update the UI
8989       *             function updateTime() {
8990       *               element.text(dateFilter(new Date(), format));
8991       *             }
8992       *
8993       *             // watch the expression, and update the UI on change.
8994       *             scope.$watch(attrs.myCurrentTime, function(value) {
8995       *               format = value;
8996       *               updateTime();
8997       *             });
8998       *
8999       *             stopTime = $interval(updateTime, 1000);
9000       *
9001       *             // listen on DOM destroy (removal) event, and cancel the next UI update
9002       *             // to prevent updating time after the DOM element was removed.
9003       *             element.bind('$destroy', function() {
9004       *               $interval.cancel(stopTime);
9005       *             });
9006       *           }
9007       *         }]);
9008       *   </script>
9009       *
9010       *   <div>
9011       *     <div ng-controller="ExampleController">
9012       *       Date format: <input ng-model="format"> <hr/>
9013       *       Current time is: <span my-current-time="format"></span>
9014       *       <hr/>
9015       *       Blood 1 : <font color='red'>{{blood_1}}</font>
9016       *       Blood 2 : <font color='red'>{{blood_2}}</font>
9017       *       <button type="button" data-ng-click="fight()">Fight</button>
9018       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
9019       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
9020       *     </div>
9021       *   </div>
9022       *
9023       * </file>
9024       * </example>
9025       */
9026     function interval(fn, delay, count, invokeApply) {
9027       var setInterval = $window.setInterval,
9028           clearInterval = $window.clearInterval,
9029           deferred = $q.defer(),
9030           promise = deferred.promise,
9031           iteration = 0,
9032           skipApply = (isDefined(invokeApply) && !invokeApply);
9033
9034       count = isDefined(count) ? count : 0;
9035
9036       promise.then(null, null, fn);
9037
9038       promise.$$intervalId = setInterval(function tick() {
9039         deferred.notify(iteration++);
9040
9041         if (count > 0 && iteration >= count) {
9042           deferred.resolve(iteration);
9043           clearInterval(promise.$$intervalId);
9044           delete intervals[promise.$$intervalId];
9045         }
9046
9047         if (!skipApply) $rootScope.$apply();
9048
9049       }, delay);
9050
9051       intervals[promise.$$intervalId] = deferred;
9052
9053       return promise;
9054     }
9055
9056
9057      /**
9058       * @ngdoc method
9059       * @name $interval#cancel
9060       *
9061       * @description
9062       * Cancels a task associated with the `promise`.
9063       *
9064       * @param {promise} promise returned by the `$interval` function.
9065       * @returns {boolean} Returns `true` if the task was successfully canceled.
9066       */
9067     interval.cancel = function(promise) {
9068       if (promise && promise.$$intervalId in intervals) {
9069         intervals[promise.$$intervalId].reject('canceled');
9070         $window.clearInterval(promise.$$intervalId);
9071         delete intervals[promise.$$intervalId];
9072         return true;
9073       }
9074       return false;
9075     };
9076
9077     return interval;
9078   }];
9079 }
9080
9081 /**
9082  * @ngdoc service
9083  * @name $locale
9084  *
9085  * @description
9086  * $locale service provides localization rules for various Angular components. As of right now the
9087  * only public api is:
9088  *
9089  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
9090  */
9091 function $LocaleProvider(){
9092   this.$get = function() {
9093     return {
9094       id: 'en-us',
9095
9096       NUMBER_FORMATS: {
9097         DECIMAL_SEP: '.',
9098         GROUP_SEP: ',',
9099         PATTERNS: [
9100           { // Decimal Pattern
9101             minInt: 1,
9102             minFrac: 0,
9103             maxFrac: 3,
9104             posPre: '',
9105             posSuf: '',
9106             negPre: '-',
9107             negSuf: '',
9108             gSize: 3,
9109             lgSize: 3
9110           },{ //Currency Pattern
9111             minInt: 1,
9112             minFrac: 2,
9113             maxFrac: 2,
9114             posPre: '\u00A4',
9115             posSuf: '',
9116             negPre: '(\u00A4',
9117             negSuf: ')',
9118             gSize: 3,
9119             lgSize: 3
9120           }
9121         ],
9122         CURRENCY_SYM: '$'
9123       },
9124
9125       DATETIME_FORMATS: {
9126         MONTH:
9127             'January,February,March,April,May,June,July,August,September,October,November,December'
9128             .split(','),
9129         SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
9130         DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
9131         SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
9132         AMPMS: ['AM','PM'],
9133         medium: 'MMM d, y h:mm:ss a',
9134         short: 'M/d/yy h:mm a',
9135         fullDate: 'EEEE, MMMM d, y',
9136         longDate: 'MMMM d, y',
9137         mediumDate: 'MMM d, y',
9138         shortDate: 'M/d/yy',
9139         mediumTime: 'h:mm:ss a',
9140         shortTime: 'h:mm a'
9141       },
9142
9143       pluralCat: function(num) {
9144         if (num === 1) {
9145           return 'one';
9146         }
9147         return 'other';
9148       }
9149     };
9150   };
9151 }
9152
9153 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
9154     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
9155 var $locationMinErr = minErr('$location');
9156
9157
9158 /**
9159  * Encode path using encodeUriSegment, ignoring forward slashes
9160  *
9161  * @param {string} path Path to encode
9162  * @returns {string}
9163  */
9164 function encodePath(path) {
9165   var segments = path.split('/'),
9166       i = segments.length;
9167
9168   while (i--) {
9169     segments[i] = encodeUriSegment(segments[i]);
9170   }
9171
9172   return segments.join('/');
9173 }
9174
9175 function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
9176   var parsedUrl = urlResolve(absoluteUrl, appBase);
9177
9178   locationObj.$$protocol = parsedUrl.protocol;
9179   locationObj.$$host = parsedUrl.hostname;
9180   locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
9181 }
9182
9183
9184 function parseAppUrl(relativeUrl, locationObj, appBase) {
9185   var prefixed = (relativeUrl.charAt(0) !== '/');
9186   if (prefixed) {
9187     relativeUrl = '/' + relativeUrl;
9188   }
9189   var match = urlResolve(relativeUrl, appBase);
9190   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
9191       match.pathname.substring(1) : match.pathname);
9192   locationObj.$$search = parseKeyValue(match.search);
9193   locationObj.$$hash = decodeURIComponent(match.hash);
9194
9195   // make sure path starts with '/';
9196   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
9197     locationObj.$$path = '/' + locationObj.$$path;
9198   }
9199 }
9200
9201
9202 /**
9203  *
9204  * @param {string} begin
9205  * @param {string} whole
9206  * @returns {string} returns text from whole after begin or undefined if it does not begin with
9207  *                   expected string.
9208  */
9209 function beginsWith(begin, whole) {
9210   if (whole.indexOf(begin) === 0) {
9211     return whole.substr(begin.length);
9212   }
9213 }
9214
9215
9216 function stripHash(url) {
9217   var index = url.indexOf('#');
9218   return index == -1 ? url : url.substr(0, index);
9219 }
9220
9221
9222 function stripFile(url) {
9223   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9224 }
9225
9226 /* return the server only (scheme://host:port) */
9227 function serverBase(url) {
9228   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9229 }
9230
9231
9232 /**
9233  * LocationHtml5Url represents an url
9234  * This object is exposed as $location service when HTML5 mode is enabled and supported
9235  *
9236  * @constructor
9237  * @param {string} appBase application base URL
9238  * @param {string} basePrefix url path prefix
9239  */
9240 function LocationHtml5Url(appBase, basePrefix) {
9241   this.$$html5 = true;
9242   basePrefix = basePrefix || '';
9243   var appBaseNoFile = stripFile(appBase);
9244   parseAbsoluteUrl(appBase, this, appBase);
9245
9246
9247   /**
9248    * Parse given html5 (regular) url string into properties
9249    * @param {string} newAbsoluteUrl HTML5 url
9250    * @private
9251    */
9252   this.$$parse = function(url) {
9253     var pathUrl = beginsWith(appBaseNoFile, url);
9254     if (!isString(pathUrl)) {
9255       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9256           appBaseNoFile);
9257     }
9258
9259     parseAppUrl(pathUrl, this, appBase);
9260
9261     if (!this.$$path) {
9262       this.$$path = '/';
9263     }
9264
9265     this.$$compose();
9266   };
9267
9268   /**
9269    * Compose url and update `absUrl` property
9270    * @private
9271    */
9272   this.$$compose = function() {
9273     var search = toKeyValue(this.$$search),
9274         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9275
9276     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9277     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9278   };
9279
9280   this.$$rewrite = function(url) {
9281     var appUrl, prevAppUrl;
9282
9283     if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
9284       prevAppUrl = appUrl;
9285       if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
9286         return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9287       } else {
9288         return appBase + prevAppUrl;
9289       }
9290     } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
9291       return appBaseNoFile + appUrl;
9292     } else if (appBaseNoFile == url + '/') {
9293       return appBaseNoFile;
9294     }
9295   };
9296 }
9297
9298
9299 /**
9300  * LocationHashbangUrl represents url
9301  * This object is exposed as $location service when developer doesn't opt into html5 mode.
9302  * It also serves as the base class for html5 mode fallback on legacy browsers.
9303  *
9304  * @constructor
9305  * @param {string} appBase application base URL
9306  * @param {string} hashPrefix hashbang prefix
9307  */
9308 function LocationHashbangUrl(appBase, hashPrefix) {
9309   var appBaseNoFile = stripFile(appBase);
9310
9311   parseAbsoluteUrl(appBase, this, appBase);
9312
9313
9314   /**
9315    * Parse given hashbang url into properties
9316    * @param {string} url Hashbang url
9317    * @private
9318    */
9319   this.$$parse = function(url) {
9320     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9321     var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9322         ? beginsWith(hashPrefix, withoutBaseUrl)
9323         : (this.$$html5)
9324           ? withoutBaseUrl
9325           : '';
9326
9327     if (!isString(withoutHashUrl)) {
9328       throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9329           hashPrefix);
9330     }
9331     parseAppUrl(withoutHashUrl, this, appBase);
9332
9333     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9334
9335     this.$$compose();
9336
9337     /*
9338      * In Windows, on an anchor node on documents loaded from
9339      * the filesystem, the browser will return a pathname
9340      * prefixed with the drive name ('/C:/path') when a
9341      * pathname without a drive is set:
9342      *  * a.setAttribute('href', '/foo')
9343      *   * a.pathname === '/C:/foo' //true
9344      *
9345      * Inside of Angular, we're always using pathnames that
9346      * do not include drive names for routing.
9347      */
9348     function removeWindowsDriveName (path, url, base) {
9349       /*
9350       Matches paths for file protocol on windows,
9351       such as /C:/foo/bar, and captures only /foo/bar.
9352       */
9353       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
9354
9355       var firstPathSegmentMatch;
9356
9357       //Get the relative path from the input URL.
9358       if (url.indexOf(base) === 0) {
9359         url = url.replace(base, '');
9360       }
9361
9362       // The input URL intentionally contains a first path segment that ends with a colon.
9363       if (windowsFilePathExp.exec(url)) {
9364         return path;
9365       }
9366
9367       firstPathSegmentMatch = windowsFilePathExp.exec(path);
9368       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9369     }
9370   };
9371
9372   /**
9373    * Compose hashbang url and update `absUrl` property
9374    * @private
9375    */
9376   this.$$compose = function() {
9377     var search = toKeyValue(this.$$search),
9378         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9379
9380     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9381     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9382   };
9383
9384   this.$$rewrite = function(url) {
9385     if(stripHash(appBase) == stripHash(url)) {
9386       return url;
9387     }
9388   };
9389 }
9390
9391
9392 /**
9393  * LocationHashbangUrl represents url
9394  * This object is exposed as $location service when html5 history api is enabled but the browser
9395  * does not support it.
9396  *
9397  * @constructor
9398  * @param {string} appBase application base URL
9399  * @param {string} hashPrefix hashbang prefix
9400  */
9401 function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9402   this.$$html5 = true;
9403   LocationHashbangUrl.apply(this, arguments);
9404
9405   var appBaseNoFile = stripFile(appBase);
9406
9407   this.$$rewrite = function(url) {
9408     var appUrl;
9409
9410     if ( appBase == stripHash(url) ) {
9411       return url;
9412     } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
9413       return appBase + hashPrefix + appUrl;
9414     } else if ( appBaseNoFile === url + '/') {
9415       return appBaseNoFile;
9416     }
9417   };
9418
9419   this.$$compose = function() {
9420     var search = toKeyValue(this.$$search),
9421         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9422
9423     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9424     // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
9425     this.$$absUrl = appBase + hashPrefix + this.$$url;
9426   };
9427
9428 }
9429
9430
9431 LocationHashbangInHtml5Url.prototype =
9432   LocationHashbangUrl.prototype =
9433   LocationHtml5Url.prototype = {
9434
9435   /**
9436    * Are we in html5 mode?
9437    * @private
9438    */
9439   $$html5: false,
9440
9441   /**
9442    * Has any change been replacing ?
9443    * @private
9444    */
9445   $$replace: false,
9446
9447   /**
9448    * @ngdoc method
9449    * @name $location#absUrl
9450    *
9451    * @description
9452    * This method is getter only.
9453    *
9454    * Return full url representation with all segments encoded according to rules specified in
9455    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9456    *
9457    * @return {string} full url
9458    */
9459   absUrl: locationGetter('$$absUrl'),
9460
9461   /**
9462    * @ngdoc method
9463    * @name $location#url
9464    *
9465    * @description
9466    * This method is getter / setter.
9467    *
9468    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9469    *
9470    * Change path, search and hash, when called with parameter and return `$location`.
9471    *
9472    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9473    * @return {string} url
9474    */
9475   url: function(url) {
9476     if (isUndefined(url))
9477       return this.$$url;
9478
9479     var match = PATH_MATCH.exec(url);
9480     if (match[1]) this.path(decodeURIComponent(match[1]));
9481     if (match[2] || match[1]) this.search(match[3] || '');
9482     this.hash(match[5] || '');
9483
9484     return this;
9485   },
9486
9487   /**
9488    * @ngdoc method
9489    * @name $location#protocol
9490    *
9491    * @description
9492    * This method is getter only.
9493    *
9494    * Return protocol of current url.
9495    *
9496    * @return {string} protocol of current url
9497    */
9498   protocol: locationGetter('$$protocol'),
9499
9500   /**
9501    * @ngdoc method
9502    * @name $location#host
9503    *
9504    * @description
9505    * This method is getter only.
9506    *
9507    * Return host of current url.
9508    *
9509    * @return {string} host of current url.
9510    */
9511   host: locationGetter('$$host'),
9512
9513   /**
9514    * @ngdoc method
9515    * @name $location#port
9516    *
9517    * @description
9518    * This method is getter only.
9519    *
9520    * Return port of current url.
9521    *
9522    * @return {Number} port
9523    */
9524   port: locationGetter('$$port'),
9525
9526   /**
9527    * @ngdoc method
9528    * @name $location#path
9529    *
9530    * @description
9531    * This method is getter / setter.
9532    *
9533    * Return path of current url when called without any parameter.
9534    *
9535    * Change path when called with parameter and return `$location`.
9536    *
9537    * Note: Path should always begin with forward slash (/), this method will add the forward slash
9538    * if it is missing.
9539    *
9540    * @param {(string|number)=} path New path
9541    * @return {string} path
9542    */
9543   path: locationGetterSetter('$$path', function(path) {
9544     path = path ? path.toString() : '';
9545     return path.charAt(0) == '/' ? path : '/' + path;
9546   }),
9547
9548   /**
9549    * @ngdoc method
9550    * @name $location#search
9551    *
9552    * @description
9553    * This method is getter / setter.
9554    *
9555    * Return search part (as object) of current url when called without any parameter.
9556    *
9557    * Change search part when called with parameter and return `$location`.
9558    *
9559    *
9560    * ```js
9561    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
9562    * var searchObject = $location.search();
9563    * // => {foo: 'bar', baz: 'xoxo'}
9564    *
9565    *
9566    * // set foo to 'yipee'
9567    * $location.search('foo', 'yipee');
9568    * // => $location
9569    * ```
9570    *
9571    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9572    * hash object.
9573    *
9574    * When called with a single argument the method acts as a setter, setting the `search` component
9575    * of `$location` to the specified value.
9576    *
9577    * If the argument is a hash object containing an array of values, these values will be encoded
9578    * as duplicate search parameters in the url.
9579    *
9580    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
9581    * will override only a single search property.
9582    *
9583    * If `paramValue` is an array, it will override the property of the `search` component of
9584    * `$location` specified via the first argument.
9585    *
9586    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
9587    *
9588    * If `paramValue` is `true`, the property specified via the first argument will be added with no
9589    * value nor trailing equal sign.
9590    *
9591    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
9592    * one or more arguments returns `$location` object itself.
9593    */
9594   search: function(search, paramValue) {
9595     switch (arguments.length) {
9596       case 0:
9597         return this.$$search;
9598       case 1:
9599         if (isString(search) || isNumber(search)) {
9600           search = search.toString();
9601           this.$$search = parseKeyValue(search);
9602         } else if (isObject(search)) {
9603           // remove object undefined or null properties
9604           forEach(search, function(value, key) {
9605             if (value == null) delete search[key];
9606           });
9607
9608           this.$$search = search;
9609         } else {
9610           throw $locationMinErr('isrcharg',
9611               'The first argument of the `$location#search()` call must be a string or an object.');
9612         }
9613         break;
9614       default:
9615         if (isUndefined(paramValue) || paramValue === null) {
9616           delete this.$$search[search];
9617         } else {
9618           this.$$search[search] = paramValue;
9619         }
9620     }
9621
9622     this.$$compose();
9623     return this;
9624   },
9625
9626   /**
9627    * @ngdoc method
9628    * @name $location#hash
9629    *
9630    * @description
9631    * This method is getter / setter.
9632    *
9633    * Return hash fragment when called without any parameter.
9634    *
9635    * Change hash fragment when called with parameter and return `$location`.
9636    *
9637    * @param {(string|number)=} hash New hash fragment
9638    * @return {string} hash
9639    */
9640   hash: locationGetterSetter('$$hash', function(hash) {
9641     return hash ? hash.toString() : '';
9642   }),
9643
9644   /**
9645    * @ngdoc method
9646    * @name $location#replace
9647    *
9648    * @description
9649    * If called, all changes to $location during current `$digest` will be replacing current history
9650    * record, instead of adding new one.
9651    */
9652   replace: function() {
9653     this.$$replace = true;
9654     return this;
9655   }
9656 };
9657
9658 function locationGetter(property) {
9659   return function() {
9660     return this[property];
9661   };
9662 }
9663
9664
9665 function locationGetterSetter(property, preprocess) {
9666   return function(value) {
9667     if (isUndefined(value))
9668       return this[property];
9669
9670     this[property] = preprocess(value);
9671     this.$$compose();
9672
9673     return this;
9674   };
9675 }
9676
9677
9678 /**
9679  * @ngdoc service
9680  * @name $location
9681  *
9682  * @requires $rootElement
9683  *
9684  * @description
9685  * The $location service parses the URL in the browser address bar (based on the
9686  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9687  * available to your application. Changes to the URL in the address bar are reflected into
9688  * $location service and changes to $location are reflected into the browser address bar.
9689  *
9690  * **The $location service:**
9691  *
9692  * - Exposes the current URL in the browser address bar, so you can
9693  *   - Watch and observe the URL.
9694  *   - Change the URL.
9695  * - Synchronizes the URL with the browser when the user
9696  *   - Changes the address bar.
9697  *   - Clicks the back or forward button (or clicks a History link).
9698  *   - Clicks on a link.
9699  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9700  *
9701  * For more information see {@link guide/$location Developer Guide: Using $location}
9702  */
9703
9704 /**
9705  * @ngdoc provider
9706  * @name $locationProvider
9707  * @description
9708  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9709  */
9710 function $LocationProvider(){
9711   var hashPrefix = '',
9712       html5Mode = false;
9713
9714   /**
9715    * @ngdoc method
9716    * @name $locationProvider#hashPrefix
9717    * @description
9718    * @param {string=} prefix Prefix for hash part (containing path and search)
9719    * @returns {*} current value if used as getter or itself (chaining) if used as setter
9720    */
9721   this.hashPrefix = function(prefix) {
9722     if (isDefined(prefix)) {
9723       hashPrefix = prefix;
9724       return this;
9725     } else {
9726       return hashPrefix;
9727     }
9728   };
9729
9730   /**
9731    * @ngdoc method
9732    * @name $locationProvider#html5Mode
9733    * @description
9734    * @param {boolean=} mode Use HTML5 strategy if available.
9735    * @returns {*} current value if used as getter or itself (chaining) if used as setter
9736    */
9737   this.html5Mode = function(mode) {
9738     if (isDefined(mode)) {
9739       html5Mode = mode;
9740       return this;
9741     } else {
9742       return html5Mode;
9743     }
9744   };
9745
9746   /**
9747    * @ngdoc event
9748    * @name $location#$locationChangeStart
9749    * @eventType broadcast on root scope
9750    * @description
9751    * Broadcasted before a URL will change. This change can be prevented by calling
9752    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9753    * details about event object. Upon successful change
9754    * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9755    *
9756    * @param {Object} angularEvent Synthetic event object.
9757    * @param {string} newUrl New URL
9758    * @param {string=} oldUrl URL that was before it was changed.
9759    */
9760
9761   /**
9762    * @ngdoc event
9763    * @name $location#$locationChangeSuccess
9764    * @eventType broadcast on root scope
9765    * @description
9766    * Broadcasted after a URL was changed.
9767    *
9768    * @param {Object} angularEvent Synthetic event object.
9769    * @param {string} newUrl New URL
9770    * @param {string=} oldUrl URL that was before it was changed.
9771    */
9772
9773   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9774       function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9775     var $location,
9776         LocationMode,
9777         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9778         initialUrl = $browser.url(),
9779         appBase;
9780
9781     if (html5Mode) {
9782       appBase = serverBase(initialUrl) + (baseHref || '/');
9783       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9784     } else {
9785       appBase = stripHash(initialUrl);
9786       LocationMode = LocationHashbangUrl;
9787     }
9788     $location = new LocationMode(appBase, '#' + hashPrefix);
9789     $location.$$parse($location.$$rewrite(initialUrl));
9790
9791     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
9792
9793     $rootElement.on('click', function(event) {
9794       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9795       // currently we open nice url link and redirect then
9796
9797       if (event.ctrlKey || event.metaKey || event.which == 2) return;
9798
9799       var elm = jqLite(event.target);
9800
9801       // traverse the DOM up to find first A tag
9802       while (lowercase(elm[0].nodeName) !== 'a') {
9803         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9804         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9805       }
9806
9807       var absHref = elm.prop('href');
9808
9809       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9810         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9811         // an animation.
9812         absHref = urlResolve(absHref.animVal).href;
9813       }
9814
9815       // Ignore when url is started with javascript: or mailto:
9816       if (IGNORE_URI_REGEXP.test(absHref)) return;
9817
9818       // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
9819       // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
9820       // somewhere#anchor or http://example.com/somewhere
9821       if (LocationMode === LocationHashbangInHtml5Url) {
9822         // get the actual href attribute - see
9823         // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9824         var href = elm.attr('href') || elm.attr('xlink:href');
9825
9826         if (href && href.indexOf('://') < 0) {         // Ignore absolute URLs
9827           var prefix = '#' + hashPrefix;
9828           if (href[0] == '/') {
9829             // absolute path - replace old path
9830             absHref = appBase + prefix + href;
9831           } else if (href[0] == '#') {
9832             // local anchor
9833             absHref = appBase + prefix + ($location.path() || '/') + href;
9834           } else {
9835             // relative path - join with current path
9836             var stack = $location.path().split("/"),
9837               parts = href.split("/");
9838             if (stack.length === 2 && !stack[1]) stack.length = 1;
9839             for (var i=0; i<parts.length; i++) {
9840               if (parts[i] == ".")
9841                 continue;
9842               else if (parts[i] == "..")
9843                 stack.pop();
9844               else if (parts[i].length)
9845                 stack.push(parts[i]);
9846             }
9847             absHref = appBase + prefix + stack.join('/');
9848           }
9849         }
9850       }
9851
9852       var rewrittenUrl = $location.$$rewrite(absHref);
9853
9854       if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9855         event.preventDefault();
9856         if (rewrittenUrl != $browser.url()) {
9857           // update location manually
9858           $location.$$parse(rewrittenUrl);
9859           $rootScope.$apply();
9860           // hack to work around FF6 bug 684208 when scenario runner clicks on links
9861           window.angular['ff-684208-preventDefault'] = true;
9862         }
9863       }
9864     });
9865
9866
9867     // rewrite hashbang url <> html5 url
9868     if ($location.absUrl() != initialUrl) {
9869       $browser.url($location.absUrl(), true);
9870     }
9871
9872     // update $location when $browser url changes
9873     $browser.onUrlChange(function(newUrl) {
9874       if ($location.absUrl() != newUrl) {
9875         $rootScope.$evalAsync(function() {
9876           var oldUrl = $location.absUrl();
9877
9878           $location.$$parse(newUrl);
9879           if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9880                                     oldUrl).defaultPrevented) {
9881             $location.$$parse(oldUrl);
9882             $browser.url(oldUrl);
9883           } else {
9884             afterLocationChange(oldUrl);
9885           }
9886         });
9887         if (!$rootScope.$$phase) $rootScope.$digest();
9888       }
9889     });
9890
9891     // update browser
9892     var changeCounter = 0;
9893     $rootScope.$watch(function $locationWatch() {
9894       var oldUrl = $browser.url();
9895       var currentReplace = $location.$$replace;
9896
9897       if (!changeCounter || oldUrl != $location.absUrl()) {
9898         changeCounter++;
9899         $rootScope.$evalAsync(function() {
9900           if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9901               defaultPrevented) {
9902             $location.$$parse(oldUrl);
9903           } else {
9904             $browser.url($location.absUrl(), currentReplace);
9905             afterLocationChange(oldUrl);
9906           }
9907         });
9908       }
9909       $location.$$replace = false;
9910
9911       return changeCounter;
9912     });
9913
9914     return $location;
9915
9916     function afterLocationChange(oldUrl) {
9917       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9918     }
9919 }];
9920 }
9921
9922 /**
9923  * @ngdoc service
9924  * @name $log
9925  * @requires $window
9926  *
9927  * @description
9928  * Simple service for logging. Default implementation safely writes the message
9929  * into the browser's console (if present).
9930  *
9931  * The main purpose of this service is to simplify debugging and troubleshooting.
9932  *
9933  * The default is to log `debug` messages. You can use
9934  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9935  *
9936  * @example
9937    <example module="logExample">
9938      <file name="script.js">
9939        angular.module('logExample', [])
9940          .controller('LogController', ['$scope', '$log', function($scope, $log) {
9941            $scope.$log = $log;
9942            $scope.message = 'Hello World!';
9943          }]);
9944      </file>
9945      <file name="index.html">
9946        <div ng-controller="LogController">
9947          <p>Reload this page with open console, enter text and hit the log button...</p>
9948          Message:
9949          <input type="text" ng-model="message"/>
9950          <button ng-click="$log.log(message)">log</button>
9951          <button ng-click="$log.warn(message)">warn</button>
9952          <button ng-click="$log.info(message)">info</button>
9953          <button ng-click="$log.error(message)">error</button>
9954        </div>
9955      </file>
9956    </example>
9957  */
9958
9959 /**
9960  * @ngdoc provider
9961  * @name $logProvider
9962  * @description
9963  * Use the `$logProvider` to configure how the application logs messages
9964  */
9965 function $LogProvider(){
9966   var debug = true,
9967       self = this;
9968
9969   /**
9970    * @ngdoc method
9971    * @name $logProvider#debugEnabled
9972    * @description
9973    * @param {boolean=} flag enable or disable debug level messages
9974    * @returns {*} current value if used as getter or itself (chaining) if used as setter
9975    */
9976   this.debugEnabled = function(flag) {
9977     if (isDefined(flag)) {
9978       debug = flag;
9979     return this;
9980     } else {
9981       return debug;
9982     }
9983   };
9984
9985   this.$get = ['$window', function($window){
9986     return {
9987       /**
9988        * @ngdoc method
9989        * @name $log#log
9990        *
9991        * @description
9992        * Write a log message
9993        */
9994       log: consoleLog('log'),
9995
9996       /**
9997        * @ngdoc method
9998        * @name $log#info
9999        *
10000        * @description
10001        * Write an information message
10002        */
10003       info: consoleLog('info'),
10004
10005       /**
10006        * @ngdoc method
10007        * @name $log#warn
10008        *
10009        * @description
10010        * Write a warning message
10011        */
10012       warn: consoleLog('warn'),
10013
10014       /**
10015        * @ngdoc method
10016        * @name $log#error
10017        *
10018        * @description
10019        * Write an error message
10020        */
10021       error: consoleLog('error'),
10022
10023       /**
10024        * @ngdoc method
10025        * @name $log#debug
10026        *
10027        * @description
10028        * Write a debug message
10029        */
10030       debug: (function () {
10031         var fn = consoleLog('debug');
10032
10033         return function() {
10034           if (debug) {
10035             fn.apply(self, arguments);
10036           }
10037         };
10038       }())
10039     };
10040
10041     function formatError(arg) {
10042       if (arg instanceof Error) {
10043         if (arg.stack) {
10044           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
10045               ? 'Error: ' + arg.message + '\n' + arg.stack
10046               : arg.stack;
10047         } else if (arg.sourceURL) {
10048           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
10049         }
10050       }
10051       return arg;
10052     }
10053
10054     function consoleLog(type) {
10055       var console = $window.console || {},
10056           logFn = console[type] || console.log || noop,
10057           hasApply = false;
10058
10059       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
10060       // The reason behind this is that console.log has type "object" in IE8...
10061       try {
10062         hasApply = !!logFn.apply;
10063       } catch (e) {}
10064
10065       if (hasApply) {
10066         return function() {
10067           var args = [];
10068           forEach(arguments, function(arg) {
10069             args.push(formatError(arg));
10070           });
10071           return logFn.apply(console, args);
10072         };
10073       }
10074
10075       // we are IE which either doesn't have window.console => this is noop and we do nothing,
10076       // or we are IE where console.log doesn't have apply so we log at least first 2 args
10077       return function(arg1, arg2) {
10078         logFn(arg1, arg2 == null ? '' : arg2);
10079       };
10080     }
10081   }];
10082 }
10083
10084 var $parseMinErr = minErr('$parse');
10085 var promiseWarningCache = {};
10086 var promiseWarning;
10087
10088 // Sandboxing Angular Expressions
10089 // ------------------------------
10090 // Angular expressions are generally considered safe because these expressions only have direct
10091 // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
10092 // obtaining a reference to native JS functions such as the Function constructor.
10093 //
10094 // As an example, consider the following Angular expression:
10095 //
10096 //   {}.toString.constructor('alert("evil JS code")')
10097 //
10098 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
10099 // against the expression language, but not to prevent exploits that were enabled by exposing
10100 // sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
10101 // practice and therefore we are not even trying to protect against interaction with an object
10102 // explicitly exposed in this way.
10103 //
10104 // In general, it is not possible to access a Window object from an angular expression unless a
10105 // window or some DOM object that has a reference to window is published onto a Scope.
10106 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
10107 // native objects.
10108
10109
10110 function ensureSafeMemberName(name, fullExpression) {
10111   if (name === "__defineGetter__" || name === "__defineSetter__"
10112       || name === "__lookupGetter__" || name === "__lookupSetter__"
10113       || name === "__proto__") {
10114     throw $parseMinErr('isecfld',
10115         'Attempting to access a disallowed field in Angular expressions! '
10116         +'Expression: {0}', fullExpression);
10117   }
10118   return name;
10119 }
10120
10121 function ensureSafeObject(obj, fullExpression) {
10122   // nifty check if obj is Function that is fast and works across iframes and other contexts
10123   if (obj) {
10124     if (obj.constructor === obj) {
10125       throw $parseMinErr('isecfn',
10126           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10127           fullExpression);
10128     } else if (// isWindow(obj)
10129         obj.document && obj.location && obj.alert && obj.setInterval) {
10130       throw $parseMinErr('isecwindow',
10131           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
10132           fullExpression);
10133     } else if (// isElement(obj)
10134         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
10135       throw $parseMinErr('isecdom',
10136           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
10137           fullExpression);
10138     } else if (// block Object so that we can't get hold of dangerous Object.* methods
10139         obj === Object) {
10140       throw $parseMinErr('isecobj',
10141           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
10142           fullExpression);
10143     }
10144   }
10145   return obj;
10146 }
10147
10148 var CALL = Function.prototype.call;
10149 var APPLY = Function.prototype.apply;
10150 var BIND = Function.prototype.bind;
10151
10152 function ensureSafeFunction(obj, fullExpression) {
10153   if (obj) {
10154     if (obj.constructor === obj) {
10155       throw $parseMinErr('isecfn',
10156         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10157         fullExpression);
10158     } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
10159       throw $parseMinErr('isecff',
10160         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
10161         fullExpression);
10162     }
10163   }
10164 }
10165
10166 var OPERATORS = {
10167     /* jshint bitwise : false */
10168     'null':function(){return null;},
10169     'true':function(){return true;},
10170     'false':function(){return false;},
10171     undefined:noop,
10172     '+':function(self, locals, a,b){
10173       a=a(self, locals); b=b(self, locals);
10174       if (isDefined(a)) {
10175         if (isDefined(b)) {
10176           return a + b;
10177         }
10178         return a;
10179       }
10180       return isDefined(b)?b:undefined;},
10181     '-':function(self, locals, a,b){
10182           a=a(self, locals); b=b(self, locals);
10183           return (isDefined(a)?a:0)-(isDefined(b)?b:0);
10184         },
10185     '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
10186     '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
10187     '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
10188     '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
10189     '=':noop,
10190     '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
10191     '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
10192     '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
10193     '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
10194     '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
10195     '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
10196     '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
10197     '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
10198     '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
10199     '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
10200     '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
10201 //    '|':function(self, locals, a,b){return a|b;},
10202     '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
10203     '!':function(self, locals, a){return !a(self, locals);}
10204 };
10205 /* jshint bitwise: true */
10206 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
10207
10208
10209 /////////////////////////////////////////
10210
10211
10212 /**
10213  * @constructor
10214  */
10215 var Lexer = function (options) {
10216   this.options = options;
10217 };
10218
10219 Lexer.prototype = {
10220   constructor: Lexer,
10221
10222   lex: function (text) {
10223     this.text = text;
10224
10225     this.index = 0;
10226     this.ch = undefined;
10227     this.lastCh = ':'; // can start regexp
10228
10229     this.tokens = [];
10230
10231     while (this.index < this.text.length) {
10232       this.ch = this.text.charAt(this.index);
10233       if (this.is('"\'')) {
10234         this.readString(this.ch);
10235       } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
10236         this.readNumber();
10237       } else if (this.isIdent(this.ch)) {
10238         this.readIdent();
10239       } else if (this.is('(){}[].,;:?')) {
10240         this.tokens.push({
10241           index: this.index,
10242           text: this.ch
10243         });
10244         this.index++;
10245       } else if (this.isWhitespace(this.ch)) {
10246         this.index++;
10247         continue;
10248       } else {
10249         var ch2 = this.ch + this.peek();
10250         var ch3 = ch2 + this.peek(2);
10251         var fn = OPERATORS[this.ch];
10252         var fn2 = OPERATORS[ch2];
10253         var fn3 = OPERATORS[ch3];
10254         if (fn3) {
10255           this.tokens.push({index: this.index, text: ch3, fn: fn3});
10256           this.index += 3;
10257         } else if (fn2) {
10258           this.tokens.push({index: this.index, text: ch2, fn: fn2});
10259           this.index += 2;
10260         } else if (fn) {
10261           this.tokens.push({
10262             index: this.index,
10263             text: this.ch,
10264             fn: fn
10265           });
10266           this.index += 1;
10267         } else {
10268           this.throwError('Unexpected next character ', this.index, this.index + 1);
10269         }
10270       }
10271       this.lastCh = this.ch;
10272     }
10273     return this.tokens;
10274   },
10275
10276   is: function(chars) {
10277     return chars.indexOf(this.ch) !== -1;
10278   },
10279
10280   was: function(chars) {
10281     return chars.indexOf(this.lastCh) !== -1;
10282   },
10283
10284   peek: function(i) {
10285     var num = i || 1;
10286     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
10287   },
10288
10289   isNumber: function(ch) {
10290     return ('0' <= ch && ch <= '9');
10291   },
10292
10293   isWhitespace: function(ch) {
10294     // IE treats non-breaking space as \u00A0
10295     return (ch === ' ' || ch === '\r' || ch === '\t' ||
10296             ch === '\n' || ch === '\v' || ch === '\u00A0');
10297   },
10298
10299   isIdent: function(ch) {
10300     return ('a' <= ch && ch <= 'z' ||
10301             'A' <= ch && ch <= 'Z' ||
10302             '_' === ch || ch === '$');
10303   },
10304
10305   isExpOperator: function(ch) {
10306     return (ch === '-' || ch === '+' || this.isNumber(ch));
10307   },
10308
10309   throwError: function(error, start, end) {
10310     end = end || this.index;
10311     var colStr = (isDefined(start)
10312             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10313             : ' ' + end);
10314     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10315         error, colStr, this.text);
10316   },
10317
10318   readNumber: function() {
10319     var number = '';
10320     var start = this.index;
10321     while (this.index < this.text.length) {
10322       var ch = lowercase(this.text.charAt(this.index));
10323       if (ch == '.' || this.isNumber(ch)) {
10324         number += ch;
10325       } else {
10326         var peekCh = this.peek();
10327         if (ch == 'e' && this.isExpOperator(peekCh)) {
10328           number += ch;
10329         } else if (this.isExpOperator(ch) &&
10330             peekCh && this.isNumber(peekCh) &&
10331             number.charAt(number.length - 1) == 'e') {
10332           number += ch;
10333         } else if (this.isExpOperator(ch) &&
10334             (!peekCh || !this.isNumber(peekCh)) &&
10335             number.charAt(number.length - 1) == 'e') {
10336           this.throwError('Invalid exponent');
10337         } else {
10338           break;
10339         }
10340       }
10341       this.index++;
10342     }
10343     number = 1 * number;
10344     this.tokens.push({
10345       index: start,
10346       text: number,
10347       literal: true,
10348       constant: true,
10349       fn: function() { return number; }
10350     });
10351   },
10352
10353   readIdent: function() {
10354     var parser = this;
10355
10356     var ident = '';
10357     var start = this.index;
10358
10359     var lastDot, peekIndex, methodName, ch;
10360
10361     while (this.index < this.text.length) {
10362       ch = this.text.charAt(this.index);
10363       if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10364         if (ch === '.') lastDot = this.index;
10365         ident += ch;
10366       } else {
10367         break;
10368       }
10369       this.index++;
10370     }
10371
10372     //check if this is not a method invocation and if it is back out to last dot
10373     if (lastDot) {
10374       peekIndex = this.index;
10375       while (peekIndex < this.text.length) {
10376         ch = this.text.charAt(peekIndex);
10377         if (ch === '(') {
10378           methodName = ident.substr(lastDot - start + 1);
10379           ident = ident.substr(0, lastDot - start);
10380           this.index = peekIndex;
10381           break;
10382         }
10383         if (this.isWhitespace(ch)) {
10384           peekIndex++;
10385         } else {
10386           break;
10387         }
10388       }
10389     }
10390
10391
10392     var token = {
10393       index: start,
10394       text: ident
10395     };
10396
10397     // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10398     if (OPERATORS.hasOwnProperty(ident)) {
10399       token.fn = OPERATORS[ident];
10400       token.literal = true;
10401       token.constant = true;
10402     } else {
10403       var getter = getterFn(ident, this.options, this.text);
10404       token.fn = extend(function(self, locals) {
10405         return (getter(self, locals));
10406       }, {
10407         assign: function(self, value) {
10408           return setter(self, ident, value, parser.text, parser.options);
10409         }
10410       });
10411     }
10412
10413     this.tokens.push(token);
10414
10415     if (methodName) {
10416       this.tokens.push({
10417         index:lastDot,
10418         text: '.'
10419       });
10420       this.tokens.push({
10421         index: lastDot + 1,
10422         text: methodName
10423       });
10424     }
10425   },
10426
10427   readString: function(quote) {
10428     var start = this.index;
10429     this.index++;
10430     var string = '';
10431     var rawString = quote;
10432     var escape = false;
10433     while (this.index < this.text.length) {
10434       var ch = this.text.charAt(this.index);
10435       rawString += ch;
10436       if (escape) {
10437         if (ch === 'u') {
10438           var hex = this.text.substring(this.index + 1, this.index + 5);
10439           if (!hex.match(/[\da-f]{4}/i))
10440             this.throwError('Invalid unicode escape [\\u' + hex + ']');
10441           this.index += 4;
10442           string += String.fromCharCode(parseInt(hex, 16));
10443         } else {
10444           var rep = ESCAPE[ch];
10445           string = string + (rep || ch);
10446         }
10447         escape = false;
10448       } else if (ch === '\\') {
10449         escape = true;
10450       } else if (ch === quote) {
10451         this.index++;
10452         this.tokens.push({
10453           index: start,
10454           text: rawString,
10455           string: string,
10456           literal: true,
10457           constant: true,
10458           fn: function() { return string; }
10459         });
10460         return;
10461       } else {
10462         string += ch;
10463       }
10464       this.index++;
10465     }
10466     this.throwError('Unterminated quote', start);
10467   }
10468 };
10469
10470
10471 /**
10472  * @constructor
10473  */
10474 var Parser = function (lexer, $filter, options) {
10475   this.lexer = lexer;
10476   this.$filter = $filter;
10477   this.options = options;
10478 };
10479
10480 Parser.ZERO = extend(function () {
10481   return 0;
10482 }, {
10483   constant: true
10484 });
10485
10486 Parser.prototype = {
10487   constructor: Parser,
10488
10489   parse: function (text) {
10490     this.text = text;
10491
10492     this.tokens = this.lexer.lex(text);
10493
10494     var value = this.statements();
10495
10496     if (this.tokens.length !== 0) {
10497       this.throwError('is an unexpected token', this.tokens[0]);
10498     }
10499
10500     value.literal = !!value.literal;
10501     value.constant = !!value.constant;
10502
10503     return value;
10504   },
10505
10506   primary: function () {
10507     var primary;
10508     if (this.expect('(')) {
10509       primary = this.filterChain();
10510       this.consume(')');
10511     } else if (this.expect('[')) {
10512       primary = this.arrayDeclaration();
10513     } else if (this.expect('{')) {
10514       primary = this.object();
10515     } else {
10516       var token = this.expect();
10517       primary = token.fn;
10518       if (!primary) {
10519         this.throwError('not a primary expression', token);
10520       }
10521       primary.literal = !!token.literal;
10522       primary.constant = !!token.constant;
10523     }
10524
10525     var next, context;
10526     while ((next = this.expect('(', '[', '.'))) {
10527       if (next.text === '(') {
10528         primary = this.functionCall(primary, context);
10529         context = null;
10530       } else if (next.text === '[') {
10531         context = primary;
10532         primary = this.objectIndex(primary);
10533       } else if (next.text === '.') {
10534         context = primary;
10535         primary = this.fieldAccess(primary);
10536       } else {
10537         this.throwError('IMPOSSIBLE');
10538       }
10539     }
10540     return primary;
10541   },
10542
10543   throwError: function(msg, token) {
10544     throw $parseMinErr('syntax',
10545         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10546           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10547   },
10548
10549   peekToken: function() {
10550     if (this.tokens.length === 0)
10551       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10552     return this.tokens[0];
10553   },
10554
10555   peek: function(e1, e2, e3, e4) {
10556     if (this.tokens.length > 0) {
10557       var token = this.tokens[0];
10558       var t = token.text;
10559       if (t === e1 || t === e2 || t === e3 || t === e4 ||
10560           (!e1 && !e2 && !e3 && !e4)) {
10561         return token;
10562       }
10563     }
10564     return false;
10565   },
10566
10567   expect: function(e1, e2, e3, e4){
10568     var token = this.peek(e1, e2, e3, e4);
10569     if (token) {
10570       this.tokens.shift();
10571       return token;
10572     }
10573     return false;
10574   },
10575
10576   consume: function(e1){
10577     if (!this.expect(e1)) {
10578       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10579     }
10580   },
10581
10582   unaryFn: function(fn, right) {
10583     return extend(function(self, locals) {
10584       return fn(self, locals, right);
10585     }, {
10586       constant:right.constant
10587     });
10588   },
10589
10590   ternaryFn: function(left, middle, right){
10591     return extend(function(self, locals){
10592       return left(self, locals) ? middle(self, locals) : right(self, locals);
10593     }, {
10594       constant: left.constant && middle.constant && right.constant
10595     });
10596   },
10597
10598   binaryFn: function(left, fn, right) {
10599     return extend(function(self, locals) {
10600       return fn(self, locals, left, right);
10601     }, {
10602       constant:left.constant && right.constant
10603     });
10604   },
10605
10606   statements: function() {
10607     var statements = [];
10608     while (true) {
10609       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10610         statements.push(this.filterChain());
10611       if (!this.expect(';')) {
10612         // optimize for the common case where there is only one statement.
10613         // TODO(size): maybe we should not support multiple statements?
10614         return (statements.length === 1)
10615             ? statements[0]
10616             : function(self, locals) {
10617                 var value;
10618                 for (var i = 0; i < statements.length; i++) {
10619                   var statement = statements[i];
10620                   if (statement) {
10621                     value = statement(self, locals);
10622                   }
10623                 }
10624                 return value;
10625               };
10626       }
10627     }
10628   },
10629
10630   filterChain: function() {
10631     var left = this.expression();
10632     var token;
10633     while (true) {
10634       if ((token = this.expect('|'))) {
10635         left = this.binaryFn(left, token.fn, this.filter());
10636       } else {
10637         return left;
10638       }
10639     }
10640   },
10641
10642   filter: function() {
10643     var token = this.expect();
10644     var fn = this.$filter(token.text);
10645     var argsFn = [];
10646     while (true) {
10647       if ((token = this.expect(':'))) {
10648         argsFn.push(this.expression());
10649       } else {
10650         var fnInvoke = function(self, locals, input) {
10651           var args = [input];
10652           for (var i = 0; i < argsFn.length; i++) {
10653             args.push(argsFn[i](self, locals));
10654           }
10655           return fn.apply(self, args);
10656         };
10657         return function() {
10658           return fnInvoke;
10659         };
10660       }
10661     }
10662   },
10663
10664   expression: function() {
10665     return this.assignment();
10666   },
10667
10668   assignment: function() {
10669     var left = this.ternary();
10670     var right;
10671     var token;
10672     if ((token = this.expect('='))) {
10673       if (!left.assign) {
10674         this.throwError('implies assignment but [' +
10675             this.text.substring(0, token.index) + '] can not be assigned to', token);
10676       }
10677       right = this.ternary();
10678       return function(scope, locals) {
10679         return left.assign(scope, right(scope, locals), locals);
10680       };
10681     }
10682     return left;
10683   },
10684
10685   ternary: function() {
10686     var left = this.logicalOR();
10687     var middle;
10688     var token;
10689     if ((token = this.expect('?'))) {
10690       middle = this.assignment();
10691       if ((token = this.expect(':'))) {
10692         return this.ternaryFn(left, middle, this.assignment());
10693       } else {
10694         this.throwError('expected :', token);
10695       }
10696     } else {
10697       return left;
10698     }
10699   },
10700
10701   logicalOR: function() {
10702     var left = this.logicalAND();
10703     var token;
10704     while (true) {
10705       if ((token = this.expect('||'))) {
10706         left = this.binaryFn(left, token.fn, this.logicalAND());
10707       } else {
10708         return left;
10709       }
10710     }
10711   },
10712
10713   logicalAND: function() {
10714     var left = this.equality();
10715     var token;
10716     if ((token = this.expect('&&'))) {
10717       left = this.binaryFn(left, token.fn, this.logicalAND());
10718     }
10719     return left;
10720   },
10721
10722   equality: function() {
10723     var left = this.relational();
10724     var token;
10725     if ((token = this.expect('==','!=','===','!=='))) {
10726       left = this.binaryFn(left, token.fn, this.equality());
10727     }
10728     return left;
10729   },
10730
10731   relational: function() {
10732     var left = this.additive();
10733     var token;
10734     if ((token = this.expect('<', '>', '<=', '>='))) {
10735       left = this.binaryFn(left, token.fn, this.relational());
10736     }
10737     return left;
10738   },
10739
10740   additive: function() {
10741     var left = this.multiplicative();
10742     var token;
10743     while ((token = this.expect('+','-'))) {
10744       left = this.binaryFn(left, token.fn, this.multiplicative());
10745     }
10746     return left;
10747   },
10748
10749   multiplicative: function() {
10750     var left = this.unary();
10751     var token;
10752     while ((token = this.expect('*','/','%'))) {
10753       left = this.binaryFn(left, token.fn, this.unary());
10754     }
10755     return left;
10756   },
10757
10758   unary: function() {
10759     var token;
10760     if (this.expect('+')) {
10761       return this.primary();
10762     } else if ((token = this.expect('-'))) {
10763       return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10764     } else if ((token = this.expect('!'))) {
10765       return this.unaryFn(token.fn, this.unary());
10766     } else {
10767       return this.primary();
10768     }
10769   },
10770
10771   fieldAccess: function(object) {
10772     var parser = this;
10773     var field = this.expect().text;
10774     var getter = getterFn(field, this.options, this.text);
10775
10776     return extend(function(scope, locals, self) {
10777       return getter(self || object(scope, locals));
10778     }, {
10779       assign: function(scope, value, locals) {
10780         var o = object(scope, locals);
10781         if (!o) object.assign(scope, o = {});
10782         return setter(o, field, value, parser.text, parser.options);
10783       }
10784     });
10785   },
10786
10787   objectIndex: function(obj) {
10788     var parser = this;
10789
10790     var indexFn = this.expression();
10791     this.consume(']');
10792
10793     return extend(function(self, locals) {
10794       var o = obj(self, locals),
10795           i = indexFn(self, locals),
10796           v, p;
10797
10798       ensureSafeMemberName(i, parser.text);
10799       if (!o) return undefined;
10800       v = ensureSafeObject(o[i], parser.text);
10801       if (v && v.then && parser.options.unwrapPromises) {
10802         p = v;
10803         if (!('$$v' in v)) {
10804           p.$$v = undefined;
10805           p.then(function(val) { p.$$v = val; });
10806         }
10807         v = v.$$v;
10808       }
10809       return v;
10810     }, {
10811       assign: function(self, value, locals) {
10812         var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
10813         // prevent overwriting of Function.constructor which would break ensureSafeObject check
10814         var o = ensureSafeObject(obj(self, locals), parser.text);
10815         if (!o) obj.assign(self, o = {});
10816         return o[key] = value;
10817       }
10818     });
10819   },
10820
10821   functionCall: function(fn, contextGetter) {
10822     var argsFn = [];
10823     if (this.peekToken().text !== ')') {
10824       do {
10825         argsFn.push(this.expression());
10826       } while (this.expect(','));
10827     }
10828     this.consume(')');
10829
10830     var parser = this;
10831
10832     return function(scope, locals) {
10833       var args = [];
10834       var context = contextGetter ? contextGetter(scope, locals) : scope;
10835
10836       for (var i = 0; i < argsFn.length; i++) {
10837         args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
10838       }
10839       var fnPtr = fn(scope, locals, context) || noop;
10840
10841       ensureSafeObject(context, parser.text);
10842       ensureSafeFunction(fnPtr, parser.text);
10843
10844       // IE stupidity! (IE doesn't have apply for some native functions)
10845       var v = fnPtr.apply
10846             ? fnPtr.apply(context, args)
10847             : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10848
10849       return ensureSafeObject(v, parser.text);
10850     };
10851   },
10852
10853   // This is used with json array declaration
10854   arrayDeclaration: function () {
10855     var elementFns = [];
10856     var allConstant = true;
10857     if (this.peekToken().text !== ']') {
10858       do {
10859         if (this.peek(']')) {
10860           // Support trailing commas per ES5.1.
10861           break;
10862         }
10863         var elementFn = this.expression();
10864         elementFns.push(elementFn);
10865         if (!elementFn.constant) {
10866           allConstant = false;
10867         }
10868       } while (this.expect(','));
10869     }
10870     this.consume(']');
10871
10872     return extend(function(self, locals) {
10873       var array = [];
10874       for (var i = 0; i < elementFns.length; i++) {
10875         array.push(elementFns[i](self, locals));
10876       }
10877       return array;
10878     }, {
10879       literal: true,
10880       constant: allConstant
10881     });
10882   },
10883
10884   object: function () {
10885     var keyValues = [];
10886     var allConstant = true;
10887     if (this.peekToken().text !== '}') {
10888       do {
10889         if (this.peek('}')) {
10890           // Support trailing commas per ES5.1.
10891           break;
10892         }
10893         var token = this.expect(),
10894         key = token.string || token.text;
10895         this.consume(':');
10896         var value = this.expression();
10897         keyValues.push({key: key, value: value});
10898         if (!value.constant) {
10899           allConstant = false;
10900         }
10901       } while (this.expect(','));
10902     }
10903     this.consume('}');
10904
10905     return extend(function(self, locals) {
10906       var object = {};
10907       for (var i = 0; i < keyValues.length; i++) {
10908         var keyValue = keyValues[i];
10909         object[keyValue.key] = keyValue.value(self, locals);
10910       }
10911       return object;
10912     }, {
10913       literal: true,
10914       constant: allConstant
10915     });
10916   }
10917 };
10918
10919
10920 //////////////////////////////////////////////////
10921 // Parser helper functions
10922 //////////////////////////////////////////////////
10923
10924 function setter(obj, path, setValue, fullExp, options) {
10925   ensureSafeObject(obj, fullExp);
10926
10927   //needed?
10928   options = options || {};
10929
10930   var element = path.split('.'), key;
10931   for (var i = 0; element.length > 1; i++) {
10932     key = ensureSafeMemberName(element.shift(), fullExp);
10933     var propertyObj = ensureSafeObject(obj[key], fullExp);
10934     if (!propertyObj) {
10935       propertyObj = {};
10936       obj[key] = propertyObj;
10937     }
10938     obj = propertyObj;
10939     if (obj.then && options.unwrapPromises) {
10940       promiseWarning(fullExp);
10941       if (!("$$v" in obj)) {
10942         (function(promise) {
10943           promise.then(function(val) { promise.$$v = val; }); }
10944         )(obj);
10945       }
10946       if (obj.$$v === undefined) {
10947         obj.$$v = {};
10948       }
10949       obj = obj.$$v;
10950     }
10951   }
10952   key = ensureSafeMemberName(element.shift(), fullExp);
10953   ensureSafeObject(obj[key], fullExp);
10954   obj[key] = setValue;
10955   return setValue;
10956 }
10957
10958 var getterFnCache = {};
10959
10960 /**
10961  * Implementation of the "Black Hole" variant from:
10962  * - http://jsperf.com/angularjs-parse-getter/4
10963  * - http://jsperf.com/path-evaluation-simplified/7
10964  */
10965 function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10966   ensureSafeMemberName(key0, fullExp);
10967   ensureSafeMemberName(key1, fullExp);
10968   ensureSafeMemberName(key2, fullExp);
10969   ensureSafeMemberName(key3, fullExp);
10970   ensureSafeMemberName(key4, fullExp);
10971
10972   return !options.unwrapPromises
10973       ? function cspSafeGetter(scope, locals) {
10974           var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10975
10976           if (pathVal == null) return pathVal;
10977           pathVal = pathVal[key0];
10978
10979           if (!key1) return pathVal;
10980           if (pathVal == null) return undefined;
10981           pathVal = pathVal[key1];
10982
10983           if (!key2) return pathVal;
10984           if (pathVal == null) return undefined;
10985           pathVal = pathVal[key2];
10986
10987           if (!key3) return pathVal;
10988           if (pathVal == null) return undefined;
10989           pathVal = pathVal[key3];
10990
10991           if (!key4) return pathVal;
10992           if (pathVal == null) return undefined;
10993           pathVal = pathVal[key4];
10994
10995           return pathVal;
10996         }
10997       : function cspSafePromiseEnabledGetter(scope, locals) {
10998           var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10999               promise;
11000
11001           if (pathVal == null) return pathVal;
11002
11003           pathVal = pathVal[key0];
11004           if (pathVal && pathVal.then) {
11005             promiseWarning(fullExp);
11006             if (!("$$v" in pathVal)) {
11007               promise = pathVal;
11008               promise.$$v = undefined;
11009               promise.then(function(val) { promise.$$v = val; });
11010             }
11011             pathVal = pathVal.$$v;
11012           }
11013
11014           if (!key1) return pathVal;
11015           if (pathVal == null) return undefined;
11016           pathVal = pathVal[key1];
11017           if (pathVal && pathVal.then) {
11018             promiseWarning(fullExp);
11019             if (!("$$v" in pathVal)) {
11020               promise = pathVal;
11021               promise.$$v = undefined;
11022               promise.then(function(val) { promise.$$v = val; });
11023             }
11024             pathVal = pathVal.$$v;
11025           }
11026
11027           if (!key2) return pathVal;
11028           if (pathVal == null) return undefined;
11029           pathVal = pathVal[key2];
11030           if (pathVal && pathVal.then) {
11031             promiseWarning(fullExp);
11032             if (!("$$v" in pathVal)) {
11033               promise = pathVal;
11034               promise.$$v = undefined;
11035               promise.then(function(val) { promise.$$v = val; });
11036             }
11037             pathVal = pathVal.$$v;
11038           }
11039
11040           if (!key3) return pathVal;
11041           if (pathVal == null) return undefined;
11042           pathVal = pathVal[key3];
11043           if (pathVal && pathVal.then) {
11044             promiseWarning(fullExp);
11045             if (!("$$v" in pathVal)) {
11046               promise = pathVal;
11047               promise.$$v = undefined;
11048               promise.then(function(val) { promise.$$v = val; });
11049             }
11050             pathVal = pathVal.$$v;
11051           }
11052
11053           if (!key4) return pathVal;
11054           if (pathVal == null) return undefined;
11055           pathVal = pathVal[key4];
11056           if (pathVal && pathVal.then) {
11057             promiseWarning(fullExp);
11058             if (!("$$v" in pathVal)) {
11059               promise = pathVal;
11060               promise.$$v = undefined;
11061               promise.then(function(val) { promise.$$v = val; });
11062             }
11063             pathVal = pathVal.$$v;
11064           }
11065           return pathVal;
11066         };
11067 }
11068
11069 function getterFn(path, options, fullExp) {
11070   // Check whether the cache has this getter already.
11071   // We can use hasOwnProperty directly on the cache because we ensure,
11072   // see below, that the cache never stores a path called 'hasOwnProperty'
11073   if (getterFnCache.hasOwnProperty(path)) {
11074     return getterFnCache[path];
11075   }
11076
11077   var pathKeys = path.split('.'),
11078       pathKeysLength = pathKeys.length,
11079       fn;
11080
11081   // http://jsperf.com/angularjs-parse-getter/6
11082   if (options.csp) {
11083     if (pathKeysLength < 6) {
11084       fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
11085                           options);
11086     } else {
11087       fn = function(scope, locals) {
11088         var i = 0, val;
11089         do {
11090           val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
11091                                 pathKeys[i++], fullExp, options)(scope, locals);
11092
11093           locals = undefined; // clear after first iteration
11094           scope = val;
11095         } while (i < pathKeysLength);
11096         return val;
11097       };
11098     }
11099   } else {
11100     var code = 'var p;\n';
11101     forEach(pathKeys, function(key, index) {
11102       ensureSafeMemberName(key, fullExp);
11103       code += 'if(s == null) return undefined;\n' +
11104               's='+ (index
11105                       // we simply dereference 's' on any .dot notation
11106                       ? 's'
11107                       // but if we are first then we check locals first, and if so read it first
11108                       : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
11109               (options.unwrapPromises
11110                 ? 'if (s && s.then) {\n' +
11111                   ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
11112                   ' if (!("$$v" in s)) {\n' +
11113                     ' p=s;\n' +
11114                     ' p.$$v = undefined;\n' +
11115                     ' p.then(function(v) {p.$$v=v;});\n' +
11116                     '}\n' +
11117                   ' s=s.$$v\n' +
11118                 '}\n'
11119                 : '');
11120     });
11121     code += 'return s;';
11122
11123     /* jshint -W054 */
11124     var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
11125     /* jshint +W054 */
11126     evaledFnGetter.toString = valueFn(code);
11127     fn = options.unwrapPromises ? function(scope, locals) {
11128       return evaledFnGetter(scope, locals, promiseWarning);
11129     } : evaledFnGetter;
11130   }
11131
11132   // Only cache the value if it's not going to mess up the cache object
11133   // This is more performant that using Object.prototype.hasOwnProperty.call
11134   if (path !== 'hasOwnProperty') {
11135     getterFnCache[path] = fn;
11136   }
11137   return fn;
11138 }
11139
11140 ///////////////////////////////////
11141
11142 /**
11143  * @ngdoc service
11144  * @name $parse
11145  * @kind function
11146  *
11147  * @description
11148  *
11149  * Converts Angular {@link guide/expression expression} into a function.
11150  *
11151  * ```js
11152  *   var getter = $parse('user.name');
11153  *   var setter = getter.assign;
11154  *   var context = {user:{name:'angular'}};
11155  *   var locals = {user:{name:'local'}};
11156  *
11157  *   expect(getter(context)).toEqual('angular');
11158  *   setter(context, 'newValue');
11159  *   expect(context.user.name).toEqual('newValue');
11160  *   expect(getter(context, locals)).toEqual('local');
11161  * ```
11162  *
11163  *
11164  * @param {string} expression String expression to compile.
11165  * @returns {function(context, locals)} a function which represents the compiled expression:
11166  *
11167  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11168  *      are evaluated against (typically a scope object).
11169  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11170  *      `context`.
11171  *
11172  *    The returned function also has the following properties:
11173  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
11174  *        literal.
11175  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
11176  *        constant literals.
11177  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
11178  *        set to a function to change its value on the given context.
11179  *
11180  */
11181
11182
11183 /**
11184  * @ngdoc provider
11185  * @name $parseProvider
11186  * @kind function
11187  *
11188  * @description
11189  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
11190  *  service.
11191  */
11192 function $ParseProvider() {
11193   var cache = {};
11194
11195   var $parseOptions = {
11196     csp: false,
11197     unwrapPromises: false,
11198     logPromiseWarnings: true
11199   };
11200
11201
11202   /**
11203    * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11204    *
11205    * @ngdoc method
11206    * @name $parseProvider#unwrapPromises
11207    * @description
11208    *
11209    * **This feature is deprecated, see deprecation notes below for more info**
11210    *
11211    * If set to true (default is false), $parse will unwrap promises automatically when a promise is
11212    * found at any part of the expression. In other words, if set to true, the expression will always
11213    * result in a non-promise value.
11214    *
11215    * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
11216    * the fulfillment value is used in place of the promise while evaluating the expression.
11217    *
11218    * **Deprecation notice**
11219    *
11220    * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
11221    * dichotomy between data access in templates (accessed as raw values) and controller code
11222    * (accessed as promises).
11223    *
11224    * In most code we ended up resolving promises manually in controllers anyway and thus unifying
11225    * the model access there.
11226    *
11227    * Other downsides of automatic promise unwrapping:
11228    *
11229    * - when building components it's often desirable to receive the raw promises
11230    * - adds complexity and slows down expression evaluation
11231    * - makes expression code pre-generation unattractive due to the amount of code that needs to be
11232    *   generated
11233    * - makes IDE auto-completion and tool support hard
11234    *
11235    * **Warning Logs**
11236    *
11237    * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
11238    * promise (to reduce the noise, each expression is logged only once). To disable this logging use
11239    * `$parseProvider.logPromiseWarnings(false)` api.
11240    *
11241    *
11242    * @param {boolean=} value New value.
11243    * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11244    *                         setter.
11245    */
11246   this.unwrapPromises = function(value) {
11247     if (isDefined(value)) {
11248       $parseOptions.unwrapPromises = !!value;
11249       return this;
11250     } else {
11251       return $parseOptions.unwrapPromises;
11252     }
11253   };
11254
11255
11256   /**
11257    * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11258    *
11259    * @ngdoc method
11260    * @name $parseProvider#logPromiseWarnings
11261    * @description
11262    *
11263    * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11264    *
11265    * The default is set to `true`.
11266    *
11267    * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11268    *
11269    * @param {boolean=} value New value.
11270    * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11271    *                         setter.
11272    */
11273  this.logPromiseWarnings = function(value) {
11274     if (isDefined(value)) {
11275       $parseOptions.logPromiseWarnings = value;
11276       return this;
11277     } else {
11278       return $parseOptions.logPromiseWarnings;
11279     }
11280   };
11281
11282
11283   this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
11284     $parseOptions.csp = $sniffer.csp;
11285
11286     promiseWarning = function promiseWarningFn(fullExp) {
11287       if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11288       promiseWarningCache[fullExp] = true;
11289       $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11290           'Automatic unwrapping of promises in Angular expressions is deprecated.');
11291     };
11292
11293     return function(exp) {
11294       var parsedExpression;
11295
11296       switch (typeof exp) {
11297         case 'string':
11298
11299           if (cache.hasOwnProperty(exp)) {
11300             return cache[exp];
11301           }
11302
11303           var lexer = new Lexer($parseOptions);
11304           var parser = new Parser(lexer, $filter, $parseOptions);
11305           parsedExpression = parser.parse(exp);
11306
11307           if (exp !== 'hasOwnProperty') {
11308             // Only cache the value if it's not going to mess up the cache object
11309             // This is more performant that using Object.prototype.hasOwnProperty.call
11310             cache[exp] = parsedExpression;
11311           }
11312
11313           return parsedExpression;
11314
11315         case 'function':
11316           return exp;
11317
11318         default:
11319           return noop;
11320       }
11321     };
11322   }];
11323 }
11324
11325 /**
11326  * @ngdoc service
11327  * @name $q
11328  * @requires $rootScope
11329  *
11330  * @description
11331  * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
11332  *
11333  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11334  * interface for interacting with an object that represents the result of an action that is
11335  * performed asynchronously, and may or may not be finished at any given point in time.
11336  *
11337  * From the perspective of dealing with error handling, deferred and promise APIs are to
11338  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11339  *
11340  * ```js
11341  *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11342  *   // are available in the current lexical scope (they could have been injected or passed in).
11343  *
11344  *   function asyncGreet(name) {
11345  *     var deferred = $q.defer();
11346  *
11347  *     setTimeout(function() {
11348  *       deferred.notify('About to greet ' + name + '.');
11349  *
11350  *       if (okToGreet(name)) {
11351  *         deferred.resolve('Hello, ' + name + '!');
11352  *       } else {
11353  *         deferred.reject('Greeting ' + name + ' is not allowed.');
11354  *       }
11355  *     }, 1000);
11356  *
11357  *     return deferred.promise;
11358  *   }
11359  *
11360  *   var promise = asyncGreet('Robin Hood');
11361  *   promise.then(function(greeting) {
11362  *     alert('Success: ' + greeting);
11363  *   }, function(reason) {
11364  *     alert('Failed: ' + reason);
11365  *   }, function(update) {
11366  *     alert('Got notification: ' + update);
11367  *   });
11368  * ```
11369  *
11370  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11371  * comes in the way of guarantees that promise and deferred APIs make, see
11372  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11373  *
11374  * Additionally the promise api allows for composition that is very hard to do with the
11375  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11376  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11377  * section on serial or parallel joining of promises.
11378  *
11379  *
11380  * # The Deferred API
11381  *
11382  * A new instance of deferred is constructed by calling `$q.defer()`.
11383  *
11384  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11385  * that can be used for signaling the successful or unsuccessful completion, as well as the status
11386  * of the task.
11387  *
11388  * **Methods**
11389  *
11390  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11391  *   constructed via `$q.reject`, the promise will be rejected instead.
11392  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11393  *   resolving it with a rejection constructed via `$q.reject`.
11394  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11395  *   multiple times before the promise is either resolved or rejected.
11396  *
11397  * **Properties**
11398  *
11399  * - promise – `{Promise}` – promise object associated with this deferred.
11400  *
11401  *
11402  * # The Promise API
11403  *
11404  * A new promise instance is created when a deferred instance is created and can be retrieved by
11405  * calling `deferred.promise`.
11406  *
11407  * The purpose of the promise object is to allow for interested parties to get access to the result
11408  * of the deferred task when it completes.
11409  *
11410  * **Methods**
11411  *
11412  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11413  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11414  *   as soon as the result is available. The callbacks are called with a single argument: the result
11415  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11416  *   provide a progress indication, before the promise is resolved or rejected.
11417  *
11418  *   This method *returns a new promise* which is resolved or rejected via the return value of the
11419  *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11420  *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11421  *   method.
11422  *
11423  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11424  *
11425  * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11426  *   but to do so without modifying the final value. This is useful to release resources or do some
11427  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11428  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11429  *   more information.
11430  *
11431  *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11432  *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11433  *   make your code IE8 and Android 2.x compatible.
11434  *
11435  * # Chaining promises
11436  *
11437  * Because calling the `then` method of a promise returns a new derived promise, it is easily
11438  * possible to create a chain of promises:
11439  *
11440  * ```js
11441  *   promiseB = promiseA.then(function(result) {
11442  *     return result + 1;
11443  *   });
11444  *
11445  *   // promiseB will be resolved immediately after promiseA is resolved and its value
11446  *   // will be the result of promiseA incremented by 1
11447  * ```
11448  *
11449  * It is possible to create chains of any length and since a promise can be resolved with another
11450  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11451  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11452  * $http's response interceptors.
11453  *
11454  *
11455  * # Differences between Kris Kowal's Q and $q
11456  *
11457  *  There are two main differences:
11458  *
11459  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11460  *   mechanism in angular, which means faster propagation of resolution or rejection into your
11461  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11462  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11463  *   all the important functionality needed for common async tasks.
11464  *
11465  *  # Testing
11466  *
11467  *  ```js
11468  *    it('should simulate promise', inject(function($q, $rootScope) {
11469  *      var deferred = $q.defer();
11470  *      var promise = deferred.promise;
11471  *      var resolvedValue;
11472  *
11473  *      promise.then(function(value) { resolvedValue = value; });
11474  *      expect(resolvedValue).toBeUndefined();
11475  *
11476  *      // Simulate resolving of promise
11477  *      deferred.resolve(123);
11478  *      // Note that the 'then' function does not get called synchronously.
11479  *      // This is because we want the promise API to always be async, whether or not
11480  *      // it got called synchronously or asynchronously.
11481  *      expect(resolvedValue).toBeUndefined();
11482  *
11483  *      // Propagate promise resolution to 'then' functions using $apply().
11484  *      $rootScope.$apply();
11485  *      expect(resolvedValue).toEqual(123);
11486  *    }));
11487  *  ```
11488  */
11489 function $QProvider() {
11490
11491   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
11492     return qFactory(function(callback) {
11493       $rootScope.$evalAsync(callback);
11494     }, $exceptionHandler);
11495   }];
11496 }
11497
11498
11499 /**
11500  * Constructs a promise manager.
11501  *
11502  * @param {function(Function)} nextTick Function for executing functions in the next turn.
11503  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11504  *     debugging purposes.
11505  * @returns {object} Promise manager.
11506  */
11507 function qFactory(nextTick, exceptionHandler) {
11508
11509   /**
11510    * @ngdoc method
11511    * @name $q#defer
11512    * @kind function
11513    *
11514    * @description
11515    * Creates a `Deferred` object which represents a task which will finish in the future.
11516    *
11517    * @returns {Deferred} Returns a new instance of deferred.
11518    */
11519   var defer = function() {
11520     var pending = [],
11521         value, deferred;
11522
11523     deferred = {
11524
11525       resolve: function(val) {
11526         if (pending) {
11527           var callbacks = pending;
11528           pending = undefined;
11529           value = ref(val);
11530
11531           if (callbacks.length) {
11532             nextTick(function() {
11533               var callback;
11534               for (var i = 0, ii = callbacks.length; i < ii; i++) {
11535                 callback = callbacks[i];
11536                 value.then(callback[0], callback[1], callback[2]);
11537               }
11538             });
11539           }
11540         }
11541       },
11542
11543
11544       reject: function(reason) {
11545         deferred.resolve(createInternalRejectedPromise(reason));
11546       },
11547
11548
11549       notify: function(progress) {
11550         if (pending) {
11551           var callbacks = pending;
11552
11553           if (pending.length) {
11554             nextTick(function() {
11555               var callback;
11556               for (var i = 0, ii = callbacks.length; i < ii; i++) {
11557                 callback = callbacks[i];
11558                 callback[2](progress);
11559               }
11560             });
11561           }
11562         }
11563       },
11564
11565
11566       promise: {
11567         then: function(callback, errback, progressback) {
11568           var result = defer();
11569
11570           var wrappedCallback = function(value) {
11571             try {
11572               result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11573             } catch(e) {
11574               result.reject(e);
11575               exceptionHandler(e);
11576             }
11577           };
11578
11579           var wrappedErrback = function(reason) {
11580             try {
11581               result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11582             } catch(e) {
11583               result.reject(e);
11584               exceptionHandler(e);
11585             }
11586           };
11587
11588           var wrappedProgressback = function(progress) {
11589             try {
11590               result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11591             } catch(e) {
11592               exceptionHandler(e);
11593             }
11594           };
11595
11596           if (pending) {
11597             pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11598           } else {
11599             value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11600           }
11601
11602           return result.promise;
11603         },
11604
11605         "catch": function(callback) {
11606           return this.then(null, callback);
11607         },
11608
11609         "finally": function(callback) {
11610
11611           function makePromise(value, resolved) {
11612             var result = defer();
11613             if (resolved) {
11614               result.resolve(value);
11615             } else {
11616               result.reject(value);
11617             }
11618             return result.promise;
11619           }
11620
11621           function handleCallback(value, isResolved) {
11622             var callbackOutput = null;
11623             try {
11624               callbackOutput = (callback ||defaultCallback)();
11625             } catch(e) {
11626               return makePromise(e, false);
11627             }
11628             if (isPromiseLike(callbackOutput)) {
11629               return callbackOutput.then(function() {
11630                 return makePromise(value, isResolved);
11631               }, function(error) {
11632                 return makePromise(error, false);
11633               });
11634             } else {
11635               return makePromise(value, isResolved);
11636             }
11637           }
11638
11639           return this.then(function(value) {
11640             return handleCallback(value, true);
11641           }, function(error) {
11642             return handleCallback(error, false);
11643           });
11644         }
11645       }
11646     };
11647
11648     return deferred;
11649   };
11650
11651
11652   var ref = function(value) {
11653     if (isPromiseLike(value)) return value;
11654     return {
11655       then: function(callback) {
11656         var result = defer();
11657         nextTick(function() {
11658           result.resolve(callback(value));
11659         });
11660         return result.promise;
11661       }
11662     };
11663   };
11664
11665
11666   /**
11667    * @ngdoc method
11668    * @name $q#reject
11669    * @kind function
11670    *
11671    * @description
11672    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11673    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11674    * a promise chain, you don't need to worry about it.
11675    *
11676    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11677    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11678    * a promise error callback and you want to forward the error to the promise derived from the
11679    * current promise, you have to "rethrow" the error by returning a rejection constructed via
11680    * `reject`.
11681    *
11682    * ```js
11683    *   promiseB = promiseA.then(function(result) {
11684    *     // success: do something and resolve promiseB
11685    *     //          with the old or a new result
11686    *     return result;
11687    *   }, function(reason) {
11688    *     // error: handle the error if possible and
11689    *     //        resolve promiseB with newPromiseOrValue,
11690    *     //        otherwise forward the rejection to promiseB
11691    *     if (canHandle(reason)) {
11692    *      // handle the error and recover
11693    *      return newPromiseOrValue;
11694    *     }
11695    *     return $q.reject(reason);
11696    *   });
11697    * ```
11698    *
11699    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11700    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11701    */
11702   var reject = function(reason) {
11703     var result = defer();
11704     result.reject(reason);
11705     return result.promise;
11706   };
11707
11708   var createInternalRejectedPromise = function(reason) {
11709     return {
11710       then: function(callback, errback) {
11711         var result = defer();
11712         nextTick(function() {
11713           try {
11714             result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11715           } catch(e) {
11716             result.reject(e);
11717             exceptionHandler(e);
11718           }
11719         });
11720         return result.promise;
11721       }
11722     };
11723   };
11724
11725
11726   /**
11727    * @ngdoc method
11728    * @name $q#when
11729    * @kind function
11730    *
11731    * @description
11732    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11733    * This is useful when you are dealing with an object that might or might not be a promise, or if
11734    * the promise comes from a source that can't be trusted.
11735    *
11736    * @param {*} value Value or a promise
11737    * @returns {Promise} Returns a promise of the passed value or promise
11738    */
11739   var when = function(value, callback, errback, progressback) {
11740     var result = defer(),
11741         done;
11742
11743     var wrappedCallback = function(value) {
11744       try {
11745         return (isFunction(callback) ? callback : defaultCallback)(value);
11746       } catch (e) {
11747         exceptionHandler(e);
11748         return reject(e);
11749       }
11750     };
11751
11752     var wrappedErrback = function(reason) {
11753       try {
11754         return (isFunction(errback) ? errback : defaultErrback)(reason);
11755       } catch (e) {
11756         exceptionHandler(e);
11757         return reject(e);
11758       }
11759     };
11760
11761     var wrappedProgressback = function(progress) {
11762       try {
11763         return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11764       } catch (e) {
11765         exceptionHandler(e);
11766       }
11767     };
11768
11769     nextTick(function() {
11770       ref(value).then(function(value) {
11771         if (done) return;
11772         done = true;
11773         result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11774       }, function(reason) {
11775         if (done) return;
11776         done = true;
11777         result.resolve(wrappedErrback(reason));
11778       }, function(progress) {
11779         if (done) return;
11780         result.notify(wrappedProgressback(progress));
11781       });
11782     });
11783
11784     return result.promise;
11785   };
11786
11787
11788   function defaultCallback(value) {
11789     return value;
11790   }
11791
11792
11793   function defaultErrback(reason) {
11794     return reject(reason);
11795   }
11796
11797
11798   /**
11799    * @ngdoc method
11800    * @name $q#all
11801    * @kind function
11802    *
11803    * @description
11804    * Combines multiple promises into a single promise that is resolved when all of the input
11805    * promises are resolved.
11806    *
11807    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11808    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11809    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11810    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11811    *   with the same rejection value.
11812    */
11813   function all(promises) {
11814     var deferred = defer(),
11815         counter = 0,
11816         results = isArray(promises) ? [] : {};
11817
11818     forEach(promises, function(promise, key) {
11819       counter++;
11820       ref(promise).then(function(value) {
11821         if (results.hasOwnProperty(key)) return;
11822         results[key] = value;
11823         if (!(--counter)) deferred.resolve(results);
11824       }, function(reason) {
11825         if (results.hasOwnProperty(key)) return;
11826         deferred.reject(reason);
11827       });
11828     });
11829
11830     if (counter === 0) {
11831       deferred.resolve(results);
11832     }
11833
11834     return deferred.promise;
11835   }
11836
11837   return {
11838     defer: defer,
11839     reject: reject,
11840     when: when,
11841     all: all
11842   };
11843 }
11844
11845 function $$RAFProvider(){ //rAF
11846   this.$get = ['$window', '$timeout', function($window, $timeout) {
11847     var requestAnimationFrame = $window.requestAnimationFrame ||
11848                                 $window.webkitRequestAnimationFrame ||
11849                                 $window.mozRequestAnimationFrame;
11850
11851     var cancelAnimationFrame = $window.cancelAnimationFrame ||
11852                                $window.webkitCancelAnimationFrame ||
11853                                $window.mozCancelAnimationFrame ||
11854                                $window.webkitCancelRequestAnimationFrame;
11855
11856     var rafSupported = !!requestAnimationFrame;
11857     var raf = rafSupported
11858       ? function(fn) {
11859           var id = requestAnimationFrame(fn);
11860           return function() {
11861             cancelAnimationFrame(id);
11862           };
11863         }
11864       : function(fn) {
11865           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
11866           return function() {
11867             $timeout.cancel(timer);
11868           };
11869         };
11870
11871     raf.supported = rafSupported;
11872
11873     return raf;
11874   }];
11875 }
11876
11877 /**
11878  * DESIGN NOTES
11879  *
11880  * The design decisions behind the scope are heavily favored for speed and memory consumption.
11881  *
11882  * The typical use of scope is to watch the expressions, which most of the time return the same
11883  * value as last time so we optimize the operation.
11884  *
11885  * Closures construction is expensive in terms of speed as well as memory:
11886  *   - No closures, instead use prototypical inheritance for API
11887  *   - Internal state needs to be stored on scope directly, which means that private state is
11888  *     exposed as $$____ properties
11889  *
11890  * Loop operations are optimized by using while(count--) { ... }
11891  *   - this means that in order to keep the same order of execution as addition we have to add
11892  *     items to the array at the beginning (unshift) instead of at the end (push)
11893  *
11894  * Child scopes are created and removed often
11895  *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11896  *
11897  * There are few watches then a lot of observers. This is why you don't want the observer to be
11898  * implemented in the same way as watch. Watch requires return of initialization function which
11899  * are expensive to construct.
11900  */
11901
11902
11903 /**
11904  * @ngdoc provider
11905  * @name $rootScopeProvider
11906  * @description
11907  *
11908  * Provider for the $rootScope service.
11909  */
11910
11911 /**
11912  * @ngdoc method
11913  * @name $rootScopeProvider#digestTtl
11914  * @description
11915  *
11916  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11917  * assuming that the model is unstable.
11918  *
11919  * The current default is 10 iterations.
11920  *
11921  * In complex applications it's possible that the dependencies between `$watch`s will result in
11922  * several digest iterations. However if an application needs more than the default 10 digest
11923  * iterations for its model to stabilize then you should investigate what is causing the model to
11924  * continuously change during the digest.
11925  *
11926  * Increasing the TTL could have performance implications, so you should not change it without
11927  * proper justification.
11928  *
11929  * @param {number} limit The number of digest iterations.
11930  */
11931
11932
11933 /**
11934  * @ngdoc service
11935  * @name $rootScope
11936  * @description
11937  *
11938  * Every application has a single root {@link ng.$rootScope.Scope scope}.
11939  * All other scopes are descendant scopes of the root scope. Scopes provide separation
11940  * between the model and the view, via a mechanism for watching the model for changes.
11941  * They also provide an event emission/broadcast and subscription facility. See the
11942  * {@link guide/scope developer guide on scopes}.
11943  */
11944 function $RootScopeProvider(){
11945   var TTL = 10;
11946   var $rootScopeMinErr = minErr('$rootScope');
11947   var lastDirtyWatch = null;
11948
11949   this.digestTtl = function(value) {
11950     if (arguments.length) {
11951       TTL = value;
11952     }
11953     return TTL;
11954   };
11955
11956   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11957       function( $injector,   $exceptionHandler,   $parse,   $browser) {
11958
11959     /**
11960      * @ngdoc type
11961      * @name $rootScope.Scope
11962      *
11963      * @description
11964      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11965      * {@link auto.$injector $injector}. Child scopes are created using the
11966      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
11967      * compiled HTML template is executed.)
11968      *
11969      * Here is a simple scope snippet to show how you can interact with the scope.
11970      * ```html
11971      * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11972      * ```
11973      *
11974      * # Inheritance
11975      * A scope can inherit from a parent scope, as in this example:
11976      * ```js
11977          var parent = $rootScope;
11978          var child = parent.$new();
11979
11980          parent.salutation = "Hello";
11981          child.name = "World";
11982          expect(child.salutation).toEqual('Hello');
11983
11984          child.salutation = "Welcome";
11985          expect(child.salutation).toEqual('Welcome');
11986          expect(parent.salutation).toEqual('Hello');
11987      * ```
11988      *
11989      *
11990      * @param {Object.<string, function()>=} providers Map of service factory which need to be
11991      *                                       provided for the current scope. Defaults to {@link ng}.
11992      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11993      *                              append/override services provided by `providers`. This is handy
11994      *                              when unit-testing and having the need to override a default
11995      *                              service.
11996      * @returns {Object} Newly created scope.
11997      *
11998      */
11999     function Scope() {
12000       this.$id = nextUid();
12001       this.$$phase = this.$parent = this.$$watchers =
12002                      this.$$nextSibling = this.$$prevSibling =
12003                      this.$$childHead = this.$$childTail = null;
12004       this['this'] = this.$root =  this;
12005       this.$$destroyed = false;
12006       this.$$asyncQueue = [];
12007       this.$$postDigestQueue = [];
12008       this.$$listeners = {};
12009       this.$$listenerCount = {};
12010       this.$$isolateBindings = {};
12011     }
12012
12013     /**
12014      * @ngdoc property
12015      * @name $rootScope.Scope#$id
12016      *
12017      * @description
12018      * Unique scope ID (monotonically increasing) useful for debugging.
12019      */
12020
12021      /**
12022       * @ngdoc property
12023       * @name $rootScope.Scope#$parent
12024       *
12025       * @description
12026       * Reference to the parent scope.
12027       */
12028
12029       /**
12030        * @ngdoc property
12031        * @name $rootScope.Scope#$root
12032        *
12033        * @description
12034        * Reference to the root scope.
12035        */
12036
12037     Scope.prototype = {
12038       constructor: Scope,
12039       /**
12040        * @ngdoc method
12041        * @name $rootScope.Scope#$new
12042        * @kind function
12043        *
12044        * @description
12045        * Creates a new child {@link ng.$rootScope.Scope scope}.
12046        *
12047        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
12048        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
12049        *
12050        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
12051        * desired for the scope and its child scopes to be permanently detached from the parent and
12052        * thus stop participating in model change detection and listener notification by invoking.
12053        *
12054        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
12055        *         parent scope. The scope is isolated, as it can not see parent scope properties.
12056        *         When creating widgets, it is useful for the widget to not accidentally read parent
12057        *         state.
12058        *
12059        * @returns {Object} The newly created child scope.
12060        *
12061        */
12062       $new: function(isolate) {
12063         var ChildScope,
12064             child;
12065
12066         if (isolate) {
12067           child = new Scope();
12068           child.$root = this.$root;
12069           // ensure that there is just one async queue per $rootScope and its children
12070           child.$$asyncQueue = this.$$asyncQueue;
12071           child.$$postDigestQueue = this.$$postDigestQueue;
12072         } else {
12073           // Only create a child scope class if somebody asks for one,
12074           // but cache it to allow the VM to optimize lookups.
12075           if (!this.$$childScopeClass) {
12076             this.$$childScopeClass = function() {
12077               this.$$watchers = this.$$nextSibling =
12078                   this.$$childHead = this.$$childTail = null;
12079               this.$$listeners = {};
12080               this.$$listenerCount = {};
12081               this.$id = nextUid();
12082               this.$$childScopeClass = null;
12083             };
12084             this.$$childScopeClass.prototype = this;
12085           }
12086           child = new this.$$childScopeClass();
12087         }
12088         child['this'] = child;
12089         child.$parent = this;
12090         child.$$prevSibling = this.$$childTail;
12091         if (this.$$childHead) {
12092           this.$$childTail.$$nextSibling = child;
12093           this.$$childTail = child;
12094         } else {
12095           this.$$childHead = this.$$childTail = child;
12096         }
12097         return child;
12098       },
12099
12100       /**
12101        * @ngdoc method
12102        * @name $rootScope.Scope#$watch
12103        * @kind function
12104        *
12105        * @description
12106        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
12107        *
12108        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
12109        *   $digest()} and should return the value that will be watched. (Since
12110        *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
12111        *   `watchExpression` can execute multiple times per
12112        *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
12113        * - The `listener` is called only when the value from the current `watchExpression` and the
12114        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
12115        *   see below). Inequality is determined according to reference inequality,
12116        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
12117        *    via the `!==` Javascript operator, unless `objectEquality == true`
12118        *   (see next point)
12119        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
12120        *   according to the {@link angular.equals} function. To save the value of the object for
12121        *   later comparison, the {@link angular.copy} function is used. This therefore means that
12122        *   watching complex objects will have adverse memory and performance implications.
12123        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
12124        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
12125        *   iteration limit is 10 to prevent an infinite loop deadlock.
12126        *
12127        *
12128        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
12129        * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
12130        * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
12131        * change is detected, be prepared for multiple calls to your listener.)
12132        *
12133        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
12134        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
12135        * watcher. In rare cases, this is undesirable because the listener is called when the result
12136        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
12137        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
12138        * listener was called due to initialization.
12139        *
12140        * The example below contains an illustration of using a function as your $watch listener
12141        *
12142        *
12143        * # Example
12144        * ```js
12145            // let's assume that scope was dependency injected as the $rootScope
12146            var scope = $rootScope;
12147            scope.name = 'misko';
12148            scope.counter = 0;
12149
12150            expect(scope.counter).toEqual(0);
12151            scope.$watch('name', function(newValue, oldValue) {
12152              scope.counter = scope.counter + 1;
12153            });
12154            expect(scope.counter).toEqual(0);
12155
12156            scope.$digest();
12157            // the listener is always called during the first $digest loop after it was registered
12158            expect(scope.counter).toEqual(1);
12159
12160            scope.$digest();
12161            // but now it will not be called unless the value changes
12162            expect(scope.counter).toEqual(1);
12163
12164            scope.name = 'adam';
12165            scope.$digest();
12166            expect(scope.counter).toEqual(2);
12167
12168
12169
12170            // Using a listener function
12171            var food;
12172            scope.foodCounter = 0;
12173            expect(scope.foodCounter).toEqual(0);
12174            scope.$watch(
12175              // This is the listener function
12176              function() { return food; },
12177              // This is the change handler
12178              function(newValue, oldValue) {
12179                if ( newValue !== oldValue ) {
12180                  // Only increment the counter if the value changed
12181                  scope.foodCounter = scope.foodCounter + 1;
12182                }
12183              }
12184            );
12185            // No digest has been run so the counter will be zero
12186            expect(scope.foodCounter).toEqual(0);
12187
12188            // Run the digest but since food has not changed count will still be zero
12189            scope.$digest();
12190            expect(scope.foodCounter).toEqual(0);
12191
12192            // Update food and run digest.  Now the counter will increment
12193            food = 'cheeseburger';
12194            scope.$digest();
12195            expect(scope.foodCounter).toEqual(1);
12196
12197        * ```
12198        *
12199        *
12200        *
12201        * @param {(function()|string)} watchExpression Expression that is evaluated on each
12202        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
12203        *    a call to the `listener`.
12204        *
12205        *    - `string`: Evaluated as {@link guide/expression expression}
12206        *    - `function(scope)`: called with current `scope` as a parameter.
12207        * @param {(function()|string)=} listener Callback called whenever the return value of
12208        *   the `watchExpression` changes.
12209        *
12210        *    - `string`: Evaluated as {@link guide/expression expression}
12211        *    - `function(newValue, oldValue, scope)`: called with current and previous values as
12212        *      parameters.
12213        *
12214        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
12215        *     comparing for reference equality.
12216        * @returns {function()} Returns a deregistration function for this listener.
12217        */
12218       $watch: function(watchExp, listener, objectEquality) {
12219         var scope = this,
12220             get = compileToFn(watchExp, 'watch'),
12221             array = scope.$$watchers,
12222             watcher = {
12223               fn: listener,
12224               last: initWatchVal,
12225               get: get,
12226               exp: watchExp,
12227               eq: !!objectEquality
12228             };
12229
12230         lastDirtyWatch = null;
12231
12232         // in the case user pass string, we need to compile it, do we really need this ?
12233         if (!isFunction(listener)) {
12234           var listenFn = compileToFn(listener || noop, 'listener');
12235           watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
12236         }
12237
12238         if (typeof watchExp == 'string' && get.constant) {
12239           var originalFn = watcher.fn;
12240           watcher.fn = function(newVal, oldVal, scope) {
12241             originalFn.call(this, newVal, oldVal, scope);
12242             arrayRemove(array, watcher);
12243           };
12244         }
12245
12246         if (!array) {
12247           array = scope.$$watchers = [];
12248         }
12249         // we use unshift since we use a while loop in $digest for speed.
12250         // the while loop reads in reverse order.
12251         array.unshift(watcher);
12252
12253         return function deregisterWatch() {
12254           arrayRemove(array, watcher);
12255           lastDirtyWatch = null;
12256         };
12257       },
12258
12259
12260       /**
12261        * @ngdoc method
12262        * @name $rootScope.Scope#$watchCollection
12263        * @kind function
12264        *
12265        * @description
12266        * Shallow watches the properties of an object and fires whenever any of the properties change
12267        * (for arrays, this implies watching the array items; for object maps, this implies watching
12268        * the properties). If a change is detected, the `listener` callback is fired.
12269        *
12270        * - The `obj` collection is observed via standard $watch operation and is examined on every
12271        *   call to $digest() to see if any items have been added, removed, or moved.
12272        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
12273        *   adding, removing, and moving items belonging to an object or array.
12274        *
12275        *
12276        * # Example
12277        * ```js
12278           $scope.names = ['igor', 'matias', 'misko', 'james'];
12279           $scope.dataCount = 4;
12280
12281           $scope.$watchCollection('names', function(newNames, oldNames) {
12282             $scope.dataCount = newNames.length;
12283           });
12284
12285           expect($scope.dataCount).toEqual(4);
12286           $scope.$digest();
12287
12288           //still at 4 ... no changes
12289           expect($scope.dataCount).toEqual(4);
12290
12291           $scope.names.pop();
12292           $scope.$digest();
12293
12294           //now there's been a change
12295           expect($scope.dataCount).toEqual(3);
12296        * ```
12297        *
12298        *
12299        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12300        *    expression value should evaluate to an object or an array which is observed on each
12301        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12302        *    collection will trigger a call to the `listener`.
12303        *
12304        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12305        *    when a change is detected.
12306        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12307        *    - The `oldCollection` object is a copy of the former collection data.
12308        *      Due to performance considerations, the`oldCollection` value is computed only if the
12309        *      `listener` function declares two or more arguments.
12310        *    - The `scope` argument refers to the current scope.
12311        *
12312        * @returns {function()} Returns a de-registration function for this listener. When the
12313        *    de-registration function is executed, the internal watch operation is terminated.
12314        */
12315       $watchCollection: function(obj, listener) {
12316         var self = this;
12317         // the current value, updated on each dirty-check run
12318         var newValue;
12319         // a shallow copy of the newValue from the last dirty-check run,
12320         // updated to match newValue during dirty-check run
12321         var oldValue;
12322         // a shallow copy of the newValue from when the last change happened
12323         var veryOldValue;
12324         // only track veryOldValue if the listener is asking for it
12325         var trackVeryOldValue = (listener.length > 1);
12326         var changeDetected = 0;
12327         var objGetter = $parse(obj);
12328         var internalArray = [];
12329         var internalObject = {};
12330         var initRun = true;
12331         var oldLength = 0;
12332
12333         function $watchCollectionWatch() {
12334           newValue = objGetter(self);
12335           var newLength, key, bothNaN;
12336
12337           if (!isObject(newValue)) { // if primitive
12338             if (oldValue !== newValue) {
12339               oldValue = newValue;
12340               changeDetected++;
12341             }
12342           } else if (isArrayLike(newValue)) {
12343             if (oldValue !== internalArray) {
12344               // we are transitioning from something which was not an array into array.
12345               oldValue = internalArray;
12346               oldLength = oldValue.length = 0;
12347               changeDetected++;
12348             }
12349
12350             newLength = newValue.length;
12351
12352             if (oldLength !== newLength) {
12353               // if lengths do not match we need to trigger change notification
12354               changeDetected++;
12355               oldValue.length = oldLength = newLength;
12356             }
12357             // copy the items to oldValue and look for changes.
12358             for (var i = 0; i < newLength; i++) {
12359               bothNaN = (oldValue[i] !== oldValue[i]) &&
12360                   (newValue[i] !== newValue[i]);
12361               if (!bothNaN && (oldValue[i] !== newValue[i])) {
12362                 changeDetected++;
12363                 oldValue[i] = newValue[i];
12364               }
12365             }
12366           } else {
12367             if (oldValue !== internalObject) {
12368               // we are transitioning from something which was not an object into object.
12369               oldValue = internalObject = {};
12370               oldLength = 0;
12371               changeDetected++;
12372             }
12373             // copy the items to oldValue and look for changes.
12374             newLength = 0;
12375             for (key in newValue) {
12376               if (newValue.hasOwnProperty(key)) {
12377                 newLength++;
12378                 if (oldValue.hasOwnProperty(key)) {
12379                   bothNaN = (oldValue[key] !== oldValue[key]) &&
12380                       (newValue[key] !== newValue[key]);
12381                   if (!bothNaN && (oldValue[key] !== newValue[key])) {
12382                     changeDetected++;
12383                     oldValue[key] = newValue[key];
12384                   }
12385                 } else {
12386                   oldLength++;
12387                   oldValue[key] = newValue[key];
12388                   changeDetected++;
12389                 }
12390               }
12391             }
12392             if (oldLength > newLength) {
12393               // we used to have more keys, need to find them and destroy them.
12394               changeDetected++;
12395               for(key in oldValue) {
12396                 if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12397                   oldLength--;
12398                   delete oldValue[key];
12399                 }
12400               }
12401             }
12402           }
12403           return changeDetected;
12404         }
12405
12406         function $watchCollectionAction() {
12407           if (initRun) {
12408             initRun = false;
12409             listener(newValue, newValue, self);
12410           } else {
12411             listener(newValue, veryOldValue, self);
12412           }
12413
12414           // make a copy for the next time a collection is changed
12415           if (trackVeryOldValue) {
12416             if (!isObject(newValue)) {
12417               //primitive
12418               veryOldValue = newValue;
12419             } else if (isArrayLike(newValue)) {
12420               veryOldValue = new Array(newValue.length);
12421               for (var i = 0; i < newValue.length; i++) {
12422                 veryOldValue[i] = newValue[i];
12423               }
12424             } else { // if object
12425               veryOldValue = {};
12426               for (var key in newValue) {
12427                 if (hasOwnProperty.call(newValue, key)) {
12428                   veryOldValue[key] = newValue[key];
12429                 }
12430               }
12431             }
12432           }
12433         }
12434
12435         return this.$watch($watchCollectionWatch, $watchCollectionAction);
12436       },
12437
12438       /**
12439        * @ngdoc method
12440        * @name $rootScope.Scope#$digest
12441        * @kind function
12442        *
12443        * @description
12444        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12445        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12446        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12447        * until no more listeners are firing. This means that it is possible to get into an infinite
12448        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12449        * iterations exceeds 10.
12450        *
12451        * Usually, you don't call `$digest()` directly in
12452        * {@link ng.directive:ngController controllers} or in
12453        * {@link ng.$compileProvider#directive directives}.
12454        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12455        * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12456        *
12457        * If you want to be notified whenever `$digest()` is called,
12458        * you can register a `watchExpression` function with
12459        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12460        *
12461        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12462        *
12463        * # Example
12464        * ```js
12465            var scope = ...;
12466            scope.name = 'misko';
12467            scope.counter = 0;
12468
12469            expect(scope.counter).toEqual(0);
12470            scope.$watch('name', function(newValue, oldValue) {
12471              scope.counter = scope.counter + 1;
12472            });
12473            expect(scope.counter).toEqual(0);
12474
12475            scope.$digest();
12476            // the listener is always called during the first $digest loop after it was registered
12477            expect(scope.counter).toEqual(1);
12478
12479            scope.$digest();
12480            // but now it will not be called unless the value changes
12481            expect(scope.counter).toEqual(1);
12482
12483            scope.name = 'adam';
12484            scope.$digest();
12485            expect(scope.counter).toEqual(2);
12486        * ```
12487        *
12488        */
12489       $digest: function() {
12490         var watch, value, last,
12491             watchers,
12492             asyncQueue = this.$$asyncQueue,
12493             postDigestQueue = this.$$postDigestQueue,
12494             length,
12495             dirty, ttl = TTL,
12496             next, current, target = this,
12497             watchLog = [],
12498             logIdx, logMsg, asyncTask;
12499
12500         beginPhase('$digest');
12501         // Check for changes to browser url that happened in sync before the call to $digest
12502         $browser.$$checkUrlChange();
12503
12504         lastDirtyWatch = null;
12505
12506         do { // "while dirty" loop
12507           dirty = false;
12508           current = target;
12509
12510           while(asyncQueue.length) {
12511             try {
12512               asyncTask = asyncQueue.shift();
12513               asyncTask.scope.$eval(asyncTask.expression);
12514             } catch (e) {
12515               clearPhase();
12516               $exceptionHandler(e);
12517             }
12518             lastDirtyWatch = null;
12519           }
12520
12521           traverseScopesLoop:
12522           do { // "traverse the scopes" loop
12523             if ((watchers = current.$$watchers)) {
12524               // process our watches
12525               length = watchers.length;
12526               while (length--) {
12527                 try {
12528                   watch = watchers[length];
12529                   // Most common watches are on primitives, in which case we can short
12530                   // circuit it with === operator, only when === fails do we use .equals
12531                   if (watch) {
12532                     if ((value = watch.get(current)) !== (last = watch.last) &&
12533                         !(watch.eq
12534                             ? equals(value, last)
12535                             : (typeof value === 'number' && typeof last === 'number'
12536                                && isNaN(value) && isNaN(last)))) {
12537                       dirty = true;
12538                       lastDirtyWatch = watch;
12539                       watch.last = watch.eq ? copy(value, null) : value;
12540                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
12541                       if (ttl < 5) {
12542                         logIdx = 4 - ttl;
12543                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
12544                         logMsg = (isFunction(watch.exp))
12545                             ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12546                             : watch.exp;
12547                         logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12548                         watchLog[logIdx].push(logMsg);
12549                       }
12550                     } else if (watch === lastDirtyWatch) {
12551                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12552                       // have already been tested.
12553                       dirty = false;
12554                       break traverseScopesLoop;
12555                     }
12556                   }
12557                 } catch (e) {
12558                   clearPhase();
12559                   $exceptionHandler(e);
12560                 }
12561               }
12562             }
12563
12564             // Insanity Warning: scope depth-first traversal
12565             // yes, this code is a bit crazy, but it works and we have tests to prove it!
12566             // this piece should be kept in sync with the traversal in $broadcast
12567             if (!(next = (current.$$childHead ||
12568                 (current !== target && current.$$nextSibling)))) {
12569               while(current !== target && !(next = current.$$nextSibling)) {
12570                 current = current.$parent;
12571               }
12572             }
12573           } while ((current = next));
12574
12575           // `break traverseScopesLoop;` takes us to here
12576
12577           if((dirty || asyncQueue.length) && !(ttl--)) {
12578             clearPhase();
12579             throw $rootScopeMinErr('infdig',
12580                 '{0} $digest() iterations reached. Aborting!\n' +
12581                 'Watchers fired in the last 5 iterations: {1}',
12582                 TTL, toJson(watchLog));
12583           }
12584
12585         } while (dirty || asyncQueue.length);
12586
12587         clearPhase();
12588
12589         while(postDigestQueue.length) {
12590           try {
12591             postDigestQueue.shift()();
12592           } catch (e) {
12593             $exceptionHandler(e);
12594           }
12595         }
12596       },
12597
12598
12599       /**
12600        * @ngdoc event
12601        * @name $rootScope.Scope#$destroy
12602        * @eventType broadcast on scope being destroyed
12603        *
12604        * @description
12605        * Broadcasted when a scope and its children are being destroyed.
12606        *
12607        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12608        * clean up DOM bindings before an element is removed from the DOM.
12609        */
12610
12611       /**
12612        * @ngdoc method
12613        * @name $rootScope.Scope#$destroy
12614        * @kind function
12615        *
12616        * @description
12617        * Removes the current scope (and all of its children) from the parent scope. Removal implies
12618        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12619        * propagate to the current scope and its children. Removal also implies that the current
12620        * scope is eligible for garbage collection.
12621        *
12622        * The `$destroy()` is usually used by directives such as
12623        * {@link ng.directive:ngRepeat ngRepeat} for managing the
12624        * unrolling of the loop.
12625        *
12626        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12627        * Application code can register a `$destroy` event handler that will give it a chance to
12628        * perform any necessary cleanup.
12629        *
12630        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12631        * clean up DOM bindings before an element is removed from the DOM.
12632        */
12633       $destroy: function() {
12634         // we can't destroy the root scope or a scope that has been already destroyed
12635         if (this.$$destroyed) return;
12636         var parent = this.$parent;
12637
12638         this.$broadcast('$destroy');
12639         this.$$destroyed = true;
12640         if (this === $rootScope) return;
12641
12642         forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12643
12644         // sever all the references to parent scopes (after this cleanup, the current scope should
12645         // not be retained by any of our references and should be eligible for garbage collection)
12646         if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12647         if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12648         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12649         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12650
12651
12652         // All of the code below is bogus code that works around V8's memory leak via optimized code
12653         // and inline caches.
12654         //
12655         // see:
12656         // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12657         // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12658         // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12659
12660         this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12661             this.$$childTail = this.$root = null;
12662
12663         // don't reset these to null in case some async task tries to register a listener/watch/task
12664         this.$$listeners = {};
12665         this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12666
12667         // prevent NPEs since these methods have references to properties we nulled out
12668         this.$destroy = this.$digest = this.$apply = noop;
12669         this.$on = this.$watch = function() { return noop; };
12670       },
12671
12672       /**
12673        * @ngdoc method
12674        * @name $rootScope.Scope#$eval
12675        * @kind function
12676        *
12677        * @description
12678        * Executes the `expression` on the current scope and returns the result. Any exceptions in
12679        * the expression are propagated (uncaught). This is useful when evaluating Angular
12680        * expressions.
12681        *
12682        * # Example
12683        * ```js
12684            var scope = ng.$rootScope.Scope();
12685            scope.a = 1;
12686            scope.b = 2;
12687
12688            expect(scope.$eval('a+b')).toEqual(3);
12689            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12690        * ```
12691        *
12692        * @param {(string|function())=} expression An angular expression to be executed.
12693        *
12694        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12695        *    - `function(scope)`: execute the function with the current `scope` parameter.
12696        *
12697        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12698        * @returns {*} The result of evaluating the expression.
12699        */
12700       $eval: function(expr, locals) {
12701         return $parse(expr)(this, locals);
12702       },
12703
12704       /**
12705        * @ngdoc method
12706        * @name $rootScope.Scope#$evalAsync
12707        * @kind function
12708        *
12709        * @description
12710        * Executes the expression on the current scope at a later point in time.
12711        *
12712        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12713        * that:
12714        *
12715        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12716        *     rendering).
12717        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12718        *     `expression` execution.
12719        *
12720        * Any exceptions from the execution of the expression are forwarded to the
12721        * {@link ng.$exceptionHandler $exceptionHandler} service.
12722        *
12723        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12724        * will be scheduled. However, it is encouraged to always call code that changes the model
12725        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12726        *
12727        * @param {(string|function())=} expression An angular expression to be executed.
12728        *
12729        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12730        *    - `function(scope)`: execute the function with the current `scope` parameter.
12731        *
12732        */
12733       $evalAsync: function(expr) {
12734         // if we are outside of an $digest loop and this is the first time we are scheduling async
12735         // task also schedule async auto-flush
12736         if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12737           $browser.defer(function() {
12738             if ($rootScope.$$asyncQueue.length) {
12739               $rootScope.$digest();
12740             }
12741           });
12742         }
12743
12744         this.$$asyncQueue.push({scope: this, expression: expr});
12745       },
12746
12747       $$postDigest : function(fn) {
12748         this.$$postDigestQueue.push(fn);
12749       },
12750
12751       /**
12752        * @ngdoc method
12753        * @name $rootScope.Scope#$apply
12754        * @kind function
12755        *
12756        * @description
12757        * `$apply()` is used to execute an expression in angular from outside of the angular
12758        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12759        * Because we are calling into the angular framework we need to perform proper scope life
12760        * cycle of {@link ng.$exceptionHandler exception handling},
12761        * {@link ng.$rootScope.Scope#$digest executing watches}.
12762        *
12763        * ## Life cycle
12764        *
12765        * # Pseudo-Code of `$apply()`
12766        * ```js
12767            function $apply(expr) {
12768              try {
12769                return $eval(expr);
12770              } catch (e) {
12771                $exceptionHandler(e);
12772              } finally {
12773                $root.$digest();
12774              }
12775            }
12776        * ```
12777        *
12778        *
12779        * Scope's `$apply()` method transitions through the following stages:
12780        *
12781        * 1. The {@link guide/expression expression} is executed using the
12782        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12783        * 2. Any exceptions from the execution of the expression are forwarded to the
12784        *    {@link ng.$exceptionHandler $exceptionHandler} service.
12785        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12786        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12787        *
12788        *
12789        * @param {(string|function())=} exp An angular expression to be executed.
12790        *
12791        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12792        *    - `function(scope)`: execute the function with current `scope` parameter.
12793        *
12794        * @returns {*} The result of evaluating the expression.
12795        */
12796       $apply: function(expr) {
12797         try {
12798           beginPhase('$apply');
12799           return this.$eval(expr);
12800         } catch (e) {
12801           $exceptionHandler(e);
12802         } finally {
12803           clearPhase();
12804           try {
12805             $rootScope.$digest();
12806           } catch (e) {
12807             $exceptionHandler(e);
12808             throw e;
12809           }
12810         }
12811       },
12812
12813       /**
12814        * @ngdoc method
12815        * @name $rootScope.Scope#$on
12816        * @kind function
12817        *
12818        * @description
12819        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12820        * discussion of event life cycle.
12821        *
12822        * The event listener function format is: `function(event, args...)`. The `event` object
12823        * passed into the listener has the following attributes:
12824        *
12825        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12826        *     `$broadcast`-ed.
12827        *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12828        *   - `name` - `{string}`: name of the event.
12829        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12830        *     further event propagation (available only for events that were `$emit`-ed).
12831        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12832        *     to true.
12833        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12834        *
12835        * @param {string} name Event name to listen on.
12836        * @param {function(event, ...args)} listener Function to call when the event is emitted.
12837        * @returns {function()} Returns a deregistration function for this listener.
12838        */
12839       $on: function(name, listener) {
12840         var namedListeners = this.$$listeners[name];
12841         if (!namedListeners) {
12842           this.$$listeners[name] = namedListeners = [];
12843         }
12844         namedListeners.push(listener);
12845
12846         var current = this;
12847         do {
12848           if (!current.$$listenerCount[name]) {
12849             current.$$listenerCount[name] = 0;
12850           }
12851           current.$$listenerCount[name]++;
12852         } while ((current = current.$parent));
12853
12854         var self = this;
12855         return function() {
12856           namedListeners[indexOf(namedListeners, listener)] = null;
12857           decrementListenerCount(self, 1, name);
12858         };
12859       },
12860
12861
12862       /**
12863        * @ngdoc method
12864        * @name $rootScope.Scope#$emit
12865        * @kind function
12866        *
12867        * @description
12868        * Dispatches an event `name` upwards through the scope hierarchy notifying the
12869        * registered {@link ng.$rootScope.Scope#$on} listeners.
12870        *
12871        * The event life cycle starts at the scope on which `$emit` was called. All
12872        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12873        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12874        * registered listeners along the way. The event will stop propagating if one of the listeners
12875        * cancels it.
12876        *
12877        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12878        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12879        *
12880        * @param {string} name Event name to emit.
12881        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12882        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
12883        */
12884       $emit: function(name, args) {
12885         var empty = [],
12886             namedListeners,
12887             scope = this,
12888             stopPropagation = false,
12889             event = {
12890               name: name,
12891               targetScope: scope,
12892               stopPropagation: function() {stopPropagation = true;},
12893               preventDefault: function() {
12894                 event.defaultPrevented = true;
12895               },
12896               defaultPrevented: false
12897             },
12898             listenerArgs = concat([event], arguments, 1),
12899             i, length;
12900
12901         do {
12902           namedListeners = scope.$$listeners[name] || empty;
12903           event.currentScope = scope;
12904           for (i=0, length=namedListeners.length; i<length; i++) {
12905
12906             // if listeners were deregistered, defragment the array
12907             if (!namedListeners[i]) {
12908               namedListeners.splice(i, 1);
12909               i--;
12910               length--;
12911               continue;
12912             }
12913             try {
12914               //allow all listeners attached to the current scope to run
12915               namedListeners[i].apply(null, listenerArgs);
12916             } catch (e) {
12917               $exceptionHandler(e);
12918             }
12919           }
12920           //if any listener on the current scope stops propagation, prevent bubbling
12921           if (stopPropagation) return event;
12922           //traverse upwards
12923           scope = scope.$parent;
12924         } while (scope);
12925
12926         return event;
12927       },
12928
12929
12930       /**
12931        * @ngdoc method
12932        * @name $rootScope.Scope#$broadcast
12933        * @kind function
12934        *
12935        * @description
12936        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12937        * registered {@link ng.$rootScope.Scope#$on} listeners.
12938        *
12939        * The event life cycle starts at the scope on which `$broadcast` was called. All
12940        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12941        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12942        * scope and calls all registered listeners along the way. The event cannot be canceled.
12943        *
12944        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12945        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12946        *
12947        * @param {string} name Event name to broadcast.
12948        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12949        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
12950        */
12951       $broadcast: function(name, args) {
12952         var target = this,
12953             current = target,
12954             next = target,
12955             event = {
12956               name: name,
12957               targetScope: target,
12958               preventDefault: function() {
12959                 event.defaultPrevented = true;
12960               },
12961               defaultPrevented: false
12962             },
12963             listenerArgs = concat([event], arguments, 1),
12964             listeners, i, length;
12965
12966         //down while you can, then up and next sibling or up and next sibling until back at root
12967         while ((current = next)) {
12968           event.currentScope = current;
12969           listeners = current.$$listeners[name] || [];
12970           for (i=0, length = listeners.length; i<length; i++) {
12971             // if listeners were deregistered, defragment the array
12972             if (!listeners[i]) {
12973               listeners.splice(i, 1);
12974               i--;
12975               length--;
12976               continue;
12977             }
12978
12979             try {
12980               listeners[i].apply(null, listenerArgs);
12981             } catch(e) {
12982               $exceptionHandler(e);
12983             }
12984           }
12985
12986           // Insanity Warning: scope depth-first traversal
12987           // yes, this code is a bit crazy, but it works and we have tests to prove it!
12988           // this piece should be kept in sync with the traversal in $digest
12989           // (though it differs due to having the extra check for $$listenerCount)
12990           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12991               (current !== target && current.$$nextSibling)))) {
12992             while(current !== target && !(next = current.$$nextSibling)) {
12993               current = current.$parent;
12994             }
12995           }
12996         }
12997
12998         return event;
12999       }
13000     };
13001
13002     var $rootScope = new Scope();
13003
13004     return $rootScope;
13005
13006
13007     function beginPhase(phase) {
13008       if ($rootScope.$$phase) {
13009         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
13010       }
13011
13012       $rootScope.$$phase = phase;
13013     }
13014
13015     function clearPhase() {
13016       $rootScope.$$phase = null;
13017     }
13018
13019     function compileToFn(exp, name) {
13020       var fn = $parse(exp);
13021       assertArgFn(fn, name);
13022       return fn;
13023     }
13024
13025     function decrementListenerCount(current, count, name) {
13026       do {
13027         current.$$listenerCount[name] -= count;
13028
13029         if (current.$$listenerCount[name] === 0) {
13030           delete current.$$listenerCount[name];
13031         }
13032       } while ((current = current.$parent));
13033     }
13034
13035     /**
13036      * function used as an initial value for watchers.
13037      * because it's unique we can easily tell it apart from other values
13038      */
13039     function initWatchVal() {}
13040   }];
13041 }
13042
13043 /**
13044  * @description
13045  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
13046  */
13047 function $$SanitizeUriProvider() {
13048   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
13049     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
13050
13051   /**
13052    * @description
13053    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13054    * urls during a[href] sanitization.
13055    *
13056    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13057    *
13058    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
13059    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
13060    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
13061    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13062    *
13063    * @param {RegExp=} regexp New regexp to whitelist urls with.
13064    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13065    *    chaining otherwise.
13066    */
13067   this.aHrefSanitizationWhitelist = function(regexp) {
13068     if (isDefined(regexp)) {
13069       aHrefSanitizationWhitelist = regexp;
13070       return this;
13071     }
13072     return aHrefSanitizationWhitelist;
13073   };
13074
13075
13076   /**
13077    * @description
13078    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13079    * urls during img[src] sanitization.
13080    *
13081    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13082    *
13083    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
13084    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
13085    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
13086    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13087    *
13088    * @param {RegExp=} regexp New regexp to whitelist urls with.
13089    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13090    *    chaining otherwise.
13091    */
13092   this.imgSrcSanitizationWhitelist = function(regexp) {
13093     if (isDefined(regexp)) {
13094       imgSrcSanitizationWhitelist = regexp;
13095       return this;
13096     }
13097     return imgSrcSanitizationWhitelist;
13098   };
13099
13100   this.$get = function() {
13101     return function sanitizeUri(uri, isImage) {
13102       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
13103       var normalizedVal;
13104       // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
13105       if (!msie || msie >= 8 ) {
13106         normalizedVal = urlResolve(uri).href;
13107         if (normalizedVal !== '' && !normalizedVal.match(regex)) {
13108           return 'unsafe:'+normalizedVal;
13109         }
13110       }
13111       return uri;
13112     };
13113   };
13114 }
13115
13116 var $sceMinErr = minErr('$sce');
13117
13118 var SCE_CONTEXTS = {
13119   HTML: 'html',
13120   CSS: 'css',
13121   URL: 'url',
13122   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
13123   // url.  (e.g. ng-include, script src, templateUrl)
13124   RESOURCE_URL: 'resourceUrl',
13125   JS: 'js'
13126 };
13127
13128 // Helper functions follow.
13129
13130 // Copied from:
13131 // http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
13132 // Prereq: s is a string.
13133 function escapeForRegexp(s) {
13134   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
13135            replace(/\x08/g, '\\x08');
13136 }
13137
13138
13139 function adjustMatcher(matcher) {
13140   if (matcher === 'self') {
13141     return matcher;
13142   } else if (isString(matcher)) {
13143     // Strings match exactly except for 2 wildcards - '*' and '**'.
13144     // '*' matches any character except those from the set ':/.?&'.
13145     // '**' matches any character (like .* in a RegExp).
13146     // More than 2 *'s raises an error as it's ill defined.
13147     if (matcher.indexOf('***') > -1) {
13148       throw $sceMinErr('iwcard',
13149           'Illegal sequence *** in string matcher.  String: {0}', matcher);
13150     }
13151     matcher = escapeForRegexp(matcher).
13152                   replace('\\*\\*', '.*').
13153                   replace('\\*', '[^:/.?&;]*');
13154     return new RegExp('^' + matcher + '$');
13155   } else if (isRegExp(matcher)) {
13156     // The only other type of matcher allowed is a Regexp.
13157     // Match entire URL / disallow partial matches.
13158     // Flags are reset (i.e. no global, ignoreCase or multiline)
13159     return new RegExp('^' + matcher.source + '$');
13160   } else {
13161     throw $sceMinErr('imatcher',
13162         'Matchers may only be "self", string patterns or RegExp objects');
13163   }
13164 }
13165
13166
13167 function adjustMatchers(matchers) {
13168   var adjustedMatchers = [];
13169   if (isDefined(matchers)) {
13170     forEach(matchers, function(matcher) {
13171       adjustedMatchers.push(adjustMatcher(matcher));
13172     });
13173   }
13174   return adjustedMatchers;
13175 }
13176
13177
13178 /**
13179  * @ngdoc service
13180  * @name $sceDelegate
13181  * @kind function
13182  *
13183  * @description
13184  *
13185  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
13186  * Contextual Escaping (SCE)} services to AngularJS.
13187  *
13188  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
13189  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
13190  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
13191  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
13192  * work because `$sce` delegates to `$sceDelegate` for these operations.
13193  *
13194  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
13195  *
13196  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
13197  * can override it completely to change the behavior of `$sce`, the common case would
13198  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
13199  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
13200  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
13201  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
13202  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13203  */
13204
13205 /**
13206  * @ngdoc provider
13207  * @name $sceDelegateProvider
13208  * @description
13209  *
13210  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
13211  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
13212  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
13213  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
13214  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13215  *
13216  * For the general details about this service in Angular, read the main page for {@link ng.$sce
13217  * Strict Contextual Escaping (SCE)}.
13218  *
13219  * **Example**:  Consider the following case. <a name="example"></a>
13220  *
13221  * - your app is hosted at url `http://myapp.example.com/`
13222  * - but some of your templates are hosted on other domains you control such as
13223  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
13224  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
13225  *
13226  * Here is what a secure configuration for this scenario might look like:
13227  *
13228  * ```
13229  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
13230  *    $sceDelegateProvider.resourceUrlWhitelist([
13231  *      // Allow same origin resource loads.
13232  *      'self',
13233  *      // Allow loading from our assets domain.  Notice the difference between * and **.
13234  *      'http://srv*.assets.example.com/**'
13235  *    ]);
13236  *
13237  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
13238  *    $sceDelegateProvider.resourceUrlBlacklist([
13239  *      'http://myapp.example.com/clickThru**'
13240  *    ]);
13241  *  });
13242  * ```
13243  */
13244
13245 function $SceDelegateProvider() {
13246   this.SCE_CONTEXTS = SCE_CONTEXTS;
13247
13248   // Resource URLs can also be trusted by policy.
13249   var resourceUrlWhitelist = ['self'],
13250       resourceUrlBlacklist = [];
13251
13252   /**
13253    * @ngdoc method
13254    * @name $sceDelegateProvider#resourceUrlWhitelist
13255    * @kind function
13256    *
13257    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
13258    *     provided.  This must be an array or null.  A snapshot of this array is used so further
13259    *     changes to the array are ignored.
13260    *
13261    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13262    *     allowed in this array.
13263    *
13264    *     Note: **an empty whitelist array will block all URLs**!
13265    *
13266    * @return {Array} the currently set whitelist array.
13267    *
13268    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
13269    * same origin resource requests.
13270    *
13271    * @description
13272    * Sets/Gets the whitelist of trusted resource URLs.
13273    */
13274   this.resourceUrlWhitelist = function (value) {
13275     if (arguments.length) {
13276       resourceUrlWhitelist = adjustMatchers(value);
13277     }
13278     return resourceUrlWhitelist;
13279   };
13280
13281   /**
13282    * @ngdoc method
13283    * @name $sceDelegateProvider#resourceUrlBlacklist
13284    * @kind function
13285    *
13286    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
13287    *     provided.  This must be an array or null.  A snapshot of this array is used so further
13288    *     changes to the array are ignored.
13289    *
13290    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13291    *     allowed in this array.
13292    *
13293    *     The typical usage for the blacklist is to **block
13294    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13295    *     these would otherwise be trusted but actually return content from the redirected domain.
13296    *
13297    *     Finally, **the blacklist overrides the whitelist** and has the final say.
13298    *
13299    * @return {Array} the currently set blacklist array.
13300    *
13301    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13302    * is no blacklist.)
13303    *
13304    * @description
13305    * Sets/Gets the blacklist of trusted resource URLs.
13306    */
13307
13308   this.resourceUrlBlacklist = function (value) {
13309     if (arguments.length) {
13310       resourceUrlBlacklist = adjustMatchers(value);
13311     }
13312     return resourceUrlBlacklist;
13313   };
13314
13315   this.$get = ['$injector', function($injector) {
13316
13317     var htmlSanitizer = function htmlSanitizer(html) {
13318       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13319     };
13320
13321     if ($injector.has('$sanitize')) {
13322       htmlSanitizer = $injector.get('$sanitize');
13323     }
13324
13325
13326     function matchUrl(matcher, parsedUrl) {
13327       if (matcher === 'self') {
13328         return urlIsSameOrigin(parsedUrl);
13329       } else {
13330         // definitely a regex.  See adjustMatchers()
13331         return !!matcher.exec(parsedUrl.href);
13332       }
13333     }
13334
13335     function isResourceUrlAllowedByPolicy(url) {
13336       var parsedUrl = urlResolve(url.toString());
13337       var i, n, allowed = false;
13338       // Ensure that at least one item from the whitelist allows this url.
13339       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13340         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13341           allowed = true;
13342           break;
13343         }
13344       }
13345       if (allowed) {
13346         // Ensure that no item from the blacklist blocked this url.
13347         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13348           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13349             allowed = false;
13350             break;
13351           }
13352         }
13353       }
13354       return allowed;
13355     }
13356
13357     function generateHolderType(Base) {
13358       var holderType = function TrustedValueHolderType(trustedValue) {
13359         this.$$unwrapTrustedValue = function() {
13360           return trustedValue;
13361         };
13362       };
13363       if (Base) {
13364         holderType.prototype = new Base();
13365       }
13366       holderType.prototype.valueOf = function sceValueOf() {
13367         return this.$$unwrapTrustedValue();
13368       };
13369       holderType.prototype.toString = function sceToString() {
13370         return this.$$unwrapTrustedValue().toString();
13371       };
13372       return holderType;
13373     }
13374
13375     var trustedValueHolderBase = generateHolderType(),
13376         byType = {};
13377
13378     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13379     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13380     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13381     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13382     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13383
13384     /**
13385      * @ngdoc method
13386      * @name $sceDelegate#trustAs
13387      *
13388      * @description
13389      * Returns an object that is trusted by angular for use in specified strict
13390      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13391      * attribute interpolation, any dom event binding attribute interpolation
13392      * such as for onclick,  etc.) that uses the provided value.
13393      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13394      *
13395      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13396      *   resourceUrl, html, js and css.
13397      * @param {*} value The value that that should be considered trusted/safe.
13398      * @returns {*} A value that can be used to stand in for the provided `value` in places
13399      * where Angular expects a $sce.trustAs() return value.
13400      */
13401     function trustAs(type, trustedValue) {
13402       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13403       if (!Constructor) {
13404         throw $sceMinErr('icontext',
13405             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13406             type, trustedValue);
13407       }
13408       if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13409         return trustedValue;
13410       }
13411       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13412       // mutable objects, we ensure here that the value passed in is actually a string.
13413       if (typeof trustedValue !== 'string') {
13414         throw $sceMinErr('itype',
13415             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13416             type);
13417       }
13418       return new Constructor(trustedValue);
13419     }
13420
13421     /**
13422      * @ngdoc method
13423      * @name $sceDelegate#valueOf
13424      *
13425      * @description
13426      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13427      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13428      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13429      *
13430      * If the passed parameter is not a value that had been returned by {@link
13431      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13432      *
13433      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13434      *      call or anything else.
13435      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13436      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13437      *     `value` unchanged.
13438      */
13439     function valueOf(maybeTrusted) {
13440       if (maybeTrusted instanceof trustedValueHolderBase) {
13441         return maybeTrusted.$$unwrapTrustedValue();
13442       } else {
13443         return maybeTrusted;
13444       }
13445     }
13446
13447     /**
13448      * @ngdoc method
13449      * @name $sceDelegate#getTrusted
13450      *
13451      * @description
13452      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13453      * returns the originally supplied value if the queried context type is a supertype of the
13454      * created type.  If this condition isn't satisfied, throws an exception.
13455      *
13456      * @param {string} type The kind of context in which this value is to be used.
13457      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13458      *     `$sceDelegate.trustAs`} call.
13459      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13460      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13461      */
13462     function getTrusted(type, maybeTrusted) {
13463       if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13464         return maybeTrusted;
13465       }
13466       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13467       if (constructor && maybeTrusted instanceof constructor) {
13468         return maybeTrusted.$$unwrapTrustedValue();
13469       }
13470       // If we get here, then we may only take one of two actions.
13471       // 1. sanitize the value for the requested type, or
13472       // 2. throw an exception.
13473       if (type === SCE_CONTEXTS.RESOURCE_URL) {
13474         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13475           return maybeTrusted;
13476         } else {
13477           throw $sceMinErr('insecurl',
13478               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13479               maybeTrusted.toString());
13480         }
13481       } else if (type === SCE_CONTEXTS.HTML) {
13482         return htmlSanitizer(maybeTrusted);
13483       }
13484       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13485     }
13486
13487     return { trustAs: trustAs,
13488              getTrusted: getTrusted,
13489              valueOf: valueOf };
13490   }];
13491 }
13492
13493
13494 /**
13495  * @ngdoc provider
13496  * @name $sceProvider
13497  * @description
13498  *
13499  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13500  * -   enable/disable Strict Contextual Escaping (SCE) in a module
13501  * -   override the default implementation with a custom delegate
13502  *
13503  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13504  */
13505
13506 /* jshint maxlen: false*/
13507
13508 /**
13509  * @ngdoc service
13510  * @name $sce
13511  * @kind function
13512  *
13513  * @description
13514  *
13515  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13516  *
13517  * # Strict Contextual Escaping
13518  *
13519  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13520  * contexts to result in a value that is marked as safe to use for that context.  One example of
13521  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13522  * to these contexts as privileged or SCE contexts.
13523  *
13524  * As of version 1.2, Angular ships with SCE enabled by default.
13525  *
13526  * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13527  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13528  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13529  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13530  * to the top of your HTML document.
13531  *
13532  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13533  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13534  *
13535  * Here's an example of a binding in a privileged context:
13536  *
13537  * ```
13538  * <input ng-model="userHtml">
13539  * <div ng-bind-html="userHtml"></div>
13540  * ```
13541  *
13542  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13543  * disabled, this application allows the user to render arbitrary HTML into the DIV.
13544  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13545  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13546  * security vulnerabilities.)
13547  *
13548  * For the case of HTML, you might use a library, either on the client side, or on the server side,
13549  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13550  *
13551  * How would you ensure that every place that used these types of bindings was bound to a value that
13552  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13553  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13554  * properties/fields and forgot to update the binding to the sanitized value?
13555  *
13556  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13557  * determine that something explicitly says it's safe to use a value for binding in that
13558  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13559  * for those values that you can easily tell are safe - because they were received from your server,
13560  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13561  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13562  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13563  *
13564  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13565  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13566  * obtain values that will be accepted by SCE / privileged contexts.
13567  *
13568  *
13569  * ## How does it work?
13570  *
13571  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13572  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13573  * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13574  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13575  *
13576  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13577  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13578  * simplified):
13579  *
13580  * ```
13581  * var ngBindHtmlDirective = ['$sce', function($sce) {
13582  *   return function(scope, element, attr) {
13583  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13584  *       element.html(value || '');
13585  *     });
13586  *   };
13587  * }];
13588  * ```
13589  *
13590  * ## Impact on loading templates
13591  *
13592  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13593  * `templateUrl`'s specified by {@link guide/directive directives}.
13594  *
13595  * By default, Angular only loads templates from the same domain and protocol as the application
13596  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13597  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13598  * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13599  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13600  *
13601  * *Please note*:
13602  * The browser's
13603  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13604  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13605  * policy apply in addition to this and may further restrict whether the template is successfully
13606  * loaded.  This means that without the right CORS policy, loading templates from a different domain
13607  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13608  * browsers.
13609  *
13610  * ## This feels like too much overhead for the developer?
13611  *
13612  * It's important to remember that SCE only applies to interpolation expressions.
13613  *
13614  * If your expressions are constant literals, they're automatically trusted and you don't need to
13615  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13616  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13617  *
13618  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13619  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13620  *
13621  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13622  * templates in `ng-include` from your application's domain without having to even know about SCE.
13623  * It blocks loading templates from other domains or loading templates over http from an https
13624  * served document.  You can change these by setting your own custom {@link
13625  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13626  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13627  *
13628  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13629  * application that's secure and can be audited to verify that with much more ease than bolting
13630  * security onto an application later.
13631  *
13632  * <a name="contexts"></a>
13633  * ## What trusted context types are supported?
13634  *
13635  * | Context             | Notes          |
13636  * |---------------------|----------------|
13637  * | `$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. |
13638  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13639  * | `$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. |
13640  * | `$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. |
13641  * | `$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. |
13642  *
13643  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13644  *
13645  *  Each element in these arrays must be one of the following:
13646  *
13647  *  - **'self'**
13648  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13649  *      domain** as the application document using the **same protocol**.
13650  *  - **String** (except the special value `'self'`)
13651  *    - The string is matched against the full *normalized / absolute URL* of the resource
13652  *      being tested (substring matches are not good enough.)
13653  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13654  *      match themselves.
13655  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13656  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13657  *      in a whitelist.
13658  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13659  *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13660  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13661  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
13662  *      http://foo.example.com/templates/**).
13663  *  - **RegExp** (*see caveat below*)
13664  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13665  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13666  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13667  *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13668  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13669  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13670  *      is highly recommended to use the string patterns and only fall back to regular expressions
13671  *      if they as a last resort.
13672  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13673  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13674  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13675  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13676  *    - If you are generating your JavaScript from some other templating engine (not
13677  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13678  *      remember to escape your regular expression (and be aware that you might need more than
13679  *      one level of escaping depending on your templating engine and the way you interpolated
13680  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13681  *      enough before coding your own.  e.g. Ruby has
13682  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13683  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13684  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13685  *      Closure library's [goog.string.regExpEscape(s)](
13686  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13687  *
13688  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13689  *
13690  * ## Show me an example using SCE.
13691  *
13692  * <example module="mySceApp" deps="angular-sanitize.js">
13693  * <file name="index.html">
13694  *   <div ng-controller="myAppController as myCtrl">
13695  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13696  *     <b>User comments</b><br>
13697  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13698  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13699  *     exploit.
13700  *     <div class="well">
13701  *       <div ng-repeat="userComment in myCtrl.userComments">
13702  *         <b>{{userComment.name}}</b>:
13703  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13704  *         <br>
13705  *       </div>
13706  *     </div>
13707  *   </div>
13708  * </file>
13709  *
13710  * <file name="script.js">
13711  *   var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13712  *
13713  *   mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13714  *     var self = this;
13715  *     $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13716  *       self.userComments = userComments;
13717  *     });
13718  *     self.explicitlyTrustedHtml = $sce.trustAsHtml(
13719  *         '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13720  *         'sanitization.&quot;">Hover over this text.</span>');
13721  *   });
13722  * </file>
13723  *
13724  * <file name="test_data.json">
13725  * [
13726  *   { "name": "Alice",
13727  *     "htmlComment":
13728  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13729  *   },
13730  *   { "name": "Bob",
13731  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13732  *   }
13733  * ]
13734  * </file>
13735  *
13736  * <file name="protractor.js" type="protractor">
13737  *   describe('SCE doc demo', function() {
13738  *     it('should sanitize untrusted values', function() {
13739  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
13740  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
13741  *     });
13742  *
13743  *     it('should NOT sanitize explicitly trusted values', function() {
13744  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13745  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13746  *           'sanitization.&quot;">Hover over this text.</span>');
13747  *     });
13748  *   });
13749  * </file>
13750  * </example>
13751  *
13752  *
13753  *
13754  * ## Can I disable SCE completely?
13755  *
13756  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13757  * for little coding overhead.  It will be much harder to take an SCE disabled application and
13758  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13759  * for cases where you have a lot of existing code that was written before SCE was introduced and
13760  * you're migrating them a module at a time.
13761  *
13762  * That said, here's how you can completely disable SCE:
13763  *
13764  * ```
13765  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13766  *   // Completely disable SCE.  For demonstration purposes only!
13767  *   // Do not use in new projects.
13768  *   $sceProvider.enabled(false);
13769  * });
13770  * ```
13771  *
13772  */
13773 /* jshint maxlen: 100 */
13774
13775 function $SceProvider() {
13776   var enabled = true;
13777
13778   /**
13779    * @ngdoc method
13780    * @name $sceProvider#enabled
13781    * @kind function
13782    *
13783    * @param {boolean=} value If provided, then enables/disables SCE.
13784    * @return {boolean} true if SCE is enabled, false otherwise.
13785    *
13786    * @description
13787    * Enables/disables SCE and returns the current value.
13788    */
13789   this.enabled = function (value) {
13790     if (arguments.length) {
13791       enabled = !!value;
13792     }
13793     return enabled;
13794   };
13795
13796
13797   /* Design notes on the default implementation for SCE.
13798    *
13799    * The API contract for the SCE delegate
13800    * -------------------------------------
13801    * The SCE delegate object must provide the following 3 methods:
13802    *
13803    * - trustAs(contextEnum, value)
13804    *     This method is used to tell the SCE service that the provided value is OK to use in the
13805    *     contexts specified by contextEnum.  It must return an object that will be accepted by
13806    *     getTrusted() for a compatible contextEnum and return this value.
13807    *
13808    * - valueOf(value)
13809    *     For values that were not produced by trustAs(), return them as is.  For values that were
13810    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13811    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13812    *     such a value.
13813    *
13814    * - getTrusted(contextEnum, value)
13815    *     This function should return the a value that is safe to use in the context specified by
13816    *     contextEnum or throw and exception otherwise.
13817    *
13818    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13819    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13820    * instance, an implementation could maintain a registry of all trusted objects by context.  In
13821    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13822    * return the same object passed in if it was found in the registry under a compatible context or
13823    * throw an exception otherwise.  An implementation might only wrap values some of the time based
13824    * on some criteria.  getTrusted() might return a value and not throw an exception for special
13825    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13826    *
13827    *
13828    * A note on the inheritance model for SCE contexts
13829    * ------------------------------------------------
13830    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13831    * is purely an implementation details.
13832    *
13833    * The contract is simply this:
13834    *
13835    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13836    *     will also succeed.
13837    *
13838    * Inheritance happens to capture this in a natural way.  In some future, we
13839    * may not use inheritance anymore.  That is OK because no code outside of
13840    * sce.js and sceSpecs.js would need to be aware of this detail.
13841    */
13842
13843   this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13844                 $parse,   $sniffer,   $sceDelegate) {
13845     // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13846     // the "expression(javascript expression)" syntax which is insecure.
13847     if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13848       throw $sceMinErr('iequirks',
13849         'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13850         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13851         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13852     }
13853
13854     var sce = shallowCopy(SCE_CONTEXTS);
13855
13856     /**
13857      * @ngdoc method
13858      * @name $sce#isEnabled
13859      * @kind function
13860      *
13861      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13862      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13863      *
13864      * @description
13865      * Returns a boolean indicating if SCE is enabled.
13866      */
13867     sce.isEnabled = function () {
13868       return enabled;
13869     };
13870     sce.trustAs = $sceDelegate.trustAs;
13871     sce.getTrusted = $sceDelegate.getTrusted;
13872     sce.valueOf = $sceDelegate.valueOf;
13873
13874     if (!enabled) {
13875       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13876       sce.valueOf = identity;
13877     }
13878
13879     /**
13880      * @ngdoc method
13881      * @name $sce#parseAs
13882      *
13883      * @description
13884      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13885      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13886      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
13887      * *result*)}
13888      *
13889      * @param {string} type The kind of SCE context in which this result will be used.
13890      * @param {string} expression String expression to compile.
13891      * @returns {function(context, locals)} a function which represents the compiled expression:
13892      *
13893      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13894      *      are evaluated against (typically a scope object).
13895      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13896      *      `context`.
13897      */
13898     sce.parseAs = function sceParseAs(type, expr) {
13899       var parsed = $parse(expr);
13900       if (parsed.literal && parsed.constant) {
13901         return parsed;
13902       } else {
13903         return function sceParseAsTrusted(self, locals) {
13904           return sce.getTrusted(type, parsed(self, locals));
13905         };
13906       }
13907     };
13908
13909     /**
13910      * @ngdoc method
13911      * @name $sce#trustAs
13912      *
13913      * @description
13914      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
13915      * returns an object that is trusted by angular for use in specified strict contextual
13916      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13917      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13918      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13919      * escaping.
13920      *
13921      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13922      *   resource_url, html, js and css.
13923      * @param {*} value The value that that should be considered trusted/safe.
13924      * @returns {*} A value that can be used to stand in for the provided `value` in places
13925      * where Angular expects a $sce.trustAs() return value.
13926      */
13927
13928     /**
13929      * @ngdoc method
13930      * @name $sce#trustAsHtml
13931      *
13932      * @description
13933      * Shorthand method.  `$sce.trustAsHtml(value)` →
13934      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13935      *
13936      * @param {*} value The value to trustAs.
13937      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
13938      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13939      *     only accept expressions that are either literal constants or are the
13940      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13941      */
13942
13943     /**
13944      * @ngdoc method
13945      * @name $sce#trustAsUrl
13946      *
13947      * @description
13948      * Shorthand method.  `$sce.trustAsUrl(value)` →
13949      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13950      *
13951      * @param {*} value The value to trustAs.
13952      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
13953      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13954      *     only accept expressions that are either literal constants or are the
13955      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13956      */
13957
13958     /**
13959      * @ngdoc method
13960      * @name $sce#trustAsResourceUrl
13961      *
13962      * @description
13963      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13964      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13965      *
13966      * @param {*} value The value to trustAs.
13967      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
13968      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13969      *     only accept expressions that are either literal constants or are the return
13970      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
13971      */
13972
13973     /**
13974      * @ngdoc method
13975      * @name $sce#trustAsJs
13976      *
13977      * @description
13978      * Shorthand method.  `$sce.trustAsJs(value)` →
13979      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13980      *
13981      * @param {*} value The value to trustAs.
13982      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
13983      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13984      *     only accept expressions that are either literal constants or are the
13985      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13986      */
13987
13988     /**
13989      * @ngdoc method
13990      * @name $sce#getTrusted
13991      *
13992      * @description
13993      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
13994      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
13995      * originally supplied value if the queried context type is a supertype of the created type.
13996      * If this condition isn't satisfied, throws an exception.
13997      *
13998      * @param {string} type The kind of context in which this value is to be used.
13999      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
14000      *                         call.
14001      * @returns {*} The value the was originally provided to
14002      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
14003      *              Otherwise, throws an exception.
14004      */
14005
14006     /**
14007      * @ngdoc method
14008      * @name $sce#getTrustedHtml
14009      *
14010      * @description
14011      * Shorthand method.  `$sce.getTrustedHtml(value)` →
14012      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
14013      *
14014      * @param {*} value The value to pass to `$sce.getTrusted`.
14015      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
14016      */
14017
14018     /**
14019      * @ngdoc method
14020      * @name $sce#getTrustedCss
14021      *
14022      * @description
14023      * Shorthand method.  `$sce.getTrustedCss(value)` →
14024      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
14025      *
14026      * @param {*} value The value to pass to `$sce.getTrusted`.
14027      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
14028      */
14029
14030     /**
14031      * @ngdoc method
14032      * @name $sce#getTrustedUrl
14033      *
14034      * @description
14035      * Shorthand method.  `$sce.getTrustedUrl(value)` →
14036      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
14037      *
14038      * @param {*} value The value to pass to `$sce.getTrusted`.
14039      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
14040      */
14041
14042     /**
14043      * @ngdoc method
14044      * @name $sce#getTrustedResourceUrl
14045      *
14046      * @description
14047      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
14048      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
14049      *
14050      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
14051      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
14052      */
14053
14054     /**
14055      * @ngdoc method
14056      * @name $sce#getTrustedJs
14057      *
14058      * @description
14059      * Shorthand method.  `$sce.getTrustedJs(value)` →
14060      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
14061      *
14062      * @param {*} value The value to pass to `$sce.getTrusted`.
14063      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
14064      */
14065
14066     /**
14067      * @ngdoc method
14068      * @name $sce#parseAsHtml
14069      *
14070      * @description
14071      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
14072      *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
14073      *
14074      * @param {string} expression String expression to compile.
14075      * @returns {function(context, locals)} a function which represents the compiled expression:
14076      *
14077      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14078      *      are evaluated against (typically a scope object).
14079      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14080      *      `context`.
14081      */
14082
14083     /**
14084      * @ngdoc method
14085      * @name $sce#parseAsCss
14086      *
14087      * @description
14088      * Shorthand method.  `$sce.parseAsCss(value)` →
14089      *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
14090      *
14091      * @param {string} expression String expression to compile.
14092      * @returns {function(context, locals)} a function which represents the compiled expression:
14093      *
14094      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14095      *      are evaluated against (typically a scope object).
14096      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14097      *      `context`.
14098      */
14099
14100     /**
14101      * @ngdoc method
14102      * @name $sce#parseAsUrl
14103      *
14104      * @description
14105      * Shorthand method.  `$sce.parseAsUrl(value)` →
14106      *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
14107      *
14108      * @param {string} expression String expression to compile.
14109      * @returns {function(context, locals)} a function which represents the compiled expression:
14110      *
14111      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14112      *      are evaluated against (typically a scope object).
14113      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14114      *      `context`.
14115      */
14116
14117     /**
14118      * @ngdoc method
14119      * @name $sce#parseAsResourceUrl
14120      *
14121      * @description
14122      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
14123      *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
14124      *
14125      * @param {string} expression String expression to compile.
14126      * @returns {function(context, locals)} a function which represents the compiled expression:
14127      *
14128      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14129      *      are evaluated against (typically a scope object).
14130      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14131      *      `context`.
14132      */
14133
14134     /**
14135      * @ngdoc method
14136      * @name $sce#parseAsJs
14137      *
14138      * @description
14139      * Shorthand method.  `$sce.parseAsJs(value)` →
14140      *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
14141      *
14142      * @param {string} expression String expression to compile.
14143      * @returns {function(context, locals)} a function which represents the compiled expression:
14144      *
14145      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14146      *      are evaluated against (typically a scope object).
14147      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14148      *      `context`.
14149      */
14150
14151     // Shorthand delegations.
14152     var parse = sce.parseAs,
14153         getTrusted = sce.getTrusted,
14154         trustAs = sce.trustAs;
14155
14156     forEach(SCE_CONTEXTS, function (enumValue, name) {
14157       var lName = lowercase(name);
14158       sce[camelCase("parse_as_" + lName)] = function (expr) {
14159         return parse(enumValue, expr);
14160       };
14161       sce[camelCase("get_trusted_" + lName)] = function (value) {
14162         return getTrusted(enumValue, value);
14163       };
14164       sce[camelCase("trust_as_" + lName)] = function (value) {
14165         return trustAs(enumValue, value);
14166       };
14167     });
14168
14169     return sce;
14170   }];
14171 }
14172
14173 /**
14174  * !!! This is an undocumented "private" service !!!
14175  *
14176  * @name $sniffer
14177  * @requires $window
14178  * @requires $document
14179  *
14180  * @property {boolean} history Does the browser support html5 history api ?
14181  * @property {boolean} hashchange Does the browser support hashchange event ?
14182  * @property {boolean} transitions Does the browser support CSS transition events ?
14183  * @property {boolean} animations Does the browser support CSS animation events ?
14184  *
14185  * @description
14186  * This is very simple implementation of testing browser's features.
14187  */
14188 function $SnifferProvider() {
14189   this.$get = ['$window', '$document', function($window, $document) {
14190     var eventSupport = {},
14191         android =
14192           int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
14193         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
14194         document = $document[0] || {},
14195         documentMode = document.documentMode,
14196         vendorPrefix,
14197         vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
14198         bodyStyle = document.body && document.body.style,
14199         transitions = false,
14200         animations = false,
14201         match;
14202
14203     if (bodyStyle) {
14204       for(var prop in bodyStyle) {
14205         if(match = vendorRegex.exec(prop)) {
14206           vendorPrefix = match[0];
14207           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
14208           break;
14209         }
14210       }
14211
14212       if(!vendorPrefix) {
14213         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
14214       }
14215
14216       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
14217       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
14218
14219       if (android && (!transitions||!animations)) {
14220         transitions = isString(document.body.style.webkitTransition);
14221         animations = isString(document.body.style.webkitAnimation);
14222       }
14223     }
14224
14225
14226     return {
14227       // Android has history.pushState, but it does not update location correctly
14228       // so let's not use the history API at all.
14229       // http://code.google.com/p/android/issues/detail?id=17471
14230       // https://github.com/angular/angular.js/issues/904
14231
14232       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
14233       // so let's not use the history API also
14234       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
14235       // jshint -W018
14236       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
14237       // jshint +W018
14238       hashchange: 'onhashchange' in $window &&
14239                   // IE8 compatible mode lies
14240                   (!documentMode || documentMode > 7),
14241       hasEvent: function(event) {
14242         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
14243         // it. In particular the event is not fired when backspace or delete key are pressed or
14244         // when cut operation is performed.
14245         if (event == 'input' && msie == 9) return false;
14246
14247         if (isUndefined(eventSupport[event])) {
14248           var divElm = document.createElement('div');
14249           eventSupport[event] = 'on' + event in divElm;
14250         }
14251
14252         return eventSupport[event];
14253       },
14254       csp: csp(),
14255       vendorPrefix: vendorPrefix,
14256       transitions : transitions,
14257       animations : animations,
14258       android: android,
14259       msie : msie,
14260       msieDocumentMode: documentMode
14261     };
14262   }];
14263 }
14264
14265 function $TimeoutProvider() {
14266   this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14267        function($rootScope,   $browser,   $q,   $exceptionHandler) {
14268     var deferreds = {};
14269
14270
14271      /**
14272       * @ngdoc service
14273       * @name $timeout
14274       *
14275       * @description
14276       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
14277       * block and delegates any exceptions to
14278       * {@link ng.$exceptionHandler $exceptionHandler} service.
14279       *
14280       * The return value of registering a timeout function is a promise, which will be resolved when
14281       * the timeout is reached and the timeout function is executed.
14282       *
14283       * To cancel a timeout request, call `$timeout.cancel(promise)`.
14284       *
14285       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
14286       * synchronously flush the queue of deferred functions.
14287       *
14288       * @param {function()} fn A function, whose execution should be delayed.
14289       * @param {number=} [delay=0] Delay in milliseconds.
14290       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14291       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14292       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14293       *   promise will be resolved with is the return value of the `fn` function.
14294       *
14295       */
14296     function timeout(fn, delay, invokeApply) {
14297       var deferred = $q.defer(),
14298           promise = deferred.promise,
14299           skipApply = (isDefined(invokeApply) && !invokeApply),
14300           timeoutId;
14301
14302       timeoutId = $browser.defer(function() {
14303         try {
14304           deferred.resolve(fn());
14305         } catch(e) {
14306           deferred.reject(e);
14307           $exceptionHandler(e);
14308         }
14309         finally {
14310           delete deferreds[promise.$$timeoutId];
14311         }
14312
14313         if (!skipApply) $rootScope.$apply();
14314       }, delay);
14315
14316       promise.$$timeoutId = timeoutId;
14317       deferreds[timeoutId] = deferred;
14318
14319       return promise;
14320     }
14321
14322
14323      /**
14324       * @ngdoc method
14325       * @name $timeout#cancel
14326       *
14327       * @description
14328       * Cancels a task associated with the `promise`. As a result of this, the promise will be
14329       * resolved with a rejection.
14330       *
14331       * @param {Promise=} promise Promise returned by the `$timeout` function.
14332       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14333       *   canceled.
14334       */
14335     timeout.cancel = function(promise) {
14336       if (promise && promise.$$timeoutId in deferreds) {
14337         deferreds[promise.$$timeoutId].reject('canceled');
14338         delete deferreds[promise.$$timeoutId];
14339         return $browser.defer.cancel(promise.$$timeoutId);
14340       }
14341       return false;
14342     };
14343
14344     return timeout;
14345   }];
14346 }
14347
14348 // NOTE:  The usage of window and document instead of $window and $document here is
14349 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
14350 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14351 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14352 // doesn't know about mocked locations and resolves URLs to the real document - which is
14353 // exactly the behavior needed here.  There is little value is mocking these out for this
14354 // service.
14355 var urlParsingNode = document.createElement("a");
14356 var originUrl = urlResolve(window.location.href, true);
14357
14358
14359 /**
14360  *
14361  * Implementation Notes for non-IE browsers
14362  * ----------------------------------------
14363  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14364  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14365  * URL will be resolved into an absolute URL in the context of the application document.
14366  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14367  * properties are all populated to reflect the normalized URL.  This approach has wide
14368  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14369  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14370  *
14371  * Implementation Notes for IE
14372  * ---------------------------
14373  * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14374  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14375  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14376  * work around that by performing the parsing in a 2nd step by taking a previously normalized
14377  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14378  * properties such as protocol, hostname, port, etc.
14379  *
14380  * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14381  * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14382  * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14383  * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14384  * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14385  * method and IE < 8 is unsupported.
14386  *
14387  * References:
14388  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14389  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14390  *   http://url.spec.whatwg.org/#urlutils
14391  *   https://github.com/angular/angular.js/pull/2902
14392  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14393  *
14394  * @kind function
14395  * @param {string} url The URL to be parsed.
14396  * @description Normalizes and parses a URL.
14397  * @returns {object} Returns the normalized URL as a dictionary.
14398  *
14399  *   | member name   | Description    |
14400  *   |---------------|----------------|
14401  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14402  *   | protocol      | The protocol including the trailing colon                              |
14403  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14404  *   | search        | The search params, minus the question mark                             |
14405  *   | hash          | The hash string, minus the hash symbol
14406  *   | hostname      | The hostname
14407  *   | port          | The port, without ":"
14408  *   | pathname      | The pathname, beginning with "/"
14409  *
14410  */
14411 function urlResolve(url, base) {
14412   var href = url;
14413
14414   if (msie) {
14415     // Normalize before parse.  Refer Implementation Notes on why this is
14416     // done in two steps on IE.
14417     urlParsingNode.setAttribute("href", href);
14418     href = urlParsingNode.href;
14419   }
14420
14421   urlParsingNode.setAttribute('href', href);
14422
14423   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14424   return {
14425     href: urlParsingNode.href,
14426     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14427     host: urlParsingNode.host,
14428     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14429     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14430     hostname: urlParsingNode.hostname,
14431     port: urlParsingNode.port,
14432     pathname: (urlParsingNode.pathname.charAt(0) === '/')
14433       ? urlParsingNode.pathname
14434       : '/' + urlParsingNode.pathname
14435   };
14436 }
14437
14438 /**
14439  * Parse a request URL and determine whether this is a same-origin request as the application document.
14440  *
14441  * @param {string|object} requestUrl The url of the request as a string that will be resolved
14442  * or a parsed URL object.
14443  * @returns {boolean} Whether the request is for the same origin as the application document.
14444  */
14445 function urlIsSameOrigin(requestUrl) {
14446   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14447   return (parsed.protocol === originUrl.protocol &&
14448           parsed.host === originUrl.host);
14449 }
14450
14451 /**
14452  * @ngdoc service
14453  * @name $window
14454  *
14455  * @description
14456  * A reference to the browser's `window` object. While `window`
14457  * is globally available in JavaScript, it causes testability problems, because
14458  * it is a global variable. In angular we always refer to it through the
14459  * `$window` service, so it may be overridden, removed or mocked for testing.
14460  *
14461  * Expressions, like the one defined for the `ngClick` directive in the example
14462  * below, are evaluated with respect to the current scope.  Therefore, there is
14463  * no risk of inadvertently coding in a dependency on a global value in such an
14464  * expression.
14465  *
14466  * @example
14467    <example module="windowExample">
14468      <file name="index.html">
14469        <script>
14470          angular.module('windowExample', [])
14471            .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
14472              $scope.greeting = 'Hello, World!';
14473              $scope.doGreeting = function(greeting) {
14474                $window.alert(greeting);
14475              };
14476            }]);
14477        </script>
14478        <div ng-controller="ExampleController">
14479          <input type="text" ng-model="greeting" />
14480          <button ng-click="doGreeting(greeting)">ALERT</button>
14481        </div>
14482      </file>
14483      <file name="protractor.js" type="protractor">
14484       it('should display the greeting in the input box', function() {
14485        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14486        // If we click the button it will block the test runner
14487        // element(':button').click();
14488       });
14489      </file>
14490    </example>
14491  */
14492 function $WindowProvider(){
14493   this.$get = valueFn(window);
14494 }
14495
14496 /* global currencyFilter: true,
14497  dateFilter: true,
14498  filterFilter: true,
14499  jsonFilter: true,
14500  limitToFilter: true,
14501  lowercaseFilter: true,
14502  numberFilter: true,
14503  orderByFilter: true,
14504  uppercaseFilter: true,
14505  */
14506
14507 /**
14508  * @ngdoc provider
14509  * @name $filterProvider
14510  * @description
14511  *
14512  * Filters are just functions which transform input to an output. However filters need to be
14513  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14514  * annotated with dependencies and is responsible for creating a filter function.
14515  *
14516  * ```js
14517  *   // Filter registration
14518  *   function MyModule($provide, $filterProvider) {
14519  *     // create a service to demonstrate injection (not always needed)
14520  *     $provide.value('greet', function(name){
14521  *       return 'Hello ' + name + '!';
14522  *     });
14523  *
14524  *     // register a filter factory which uses the
14525  *     // greet service to demonstrate DI.
14526  *     $filterProvider.register('greet', function(greet){
14527  *       // return the filter function which uses the greet service
14528  *       // to generate salutation
14529  *       return function(text) {
14530  *         // filters need to be forgiving so check input validity
14531  *         return text && greet(text) || text;
14532  *       };
14533  *     });
14534  *   }
14535  * ```
14536  *
14537  * The filter function is registered with the `$injector` under the filter name suffix with
14538  * `Filter`.
14539  *
14540  * ```js
14541  *   it('should be the same instance', inject(
14542  *     function($filterProvider) {
14543  *       $filterProvider.register('reverse', function(){
14544  *         return ...;
14545  *       });
14546  *     },
14547  *     function($filter, reverseFilter) {
14548  *       expect($filter('reverse')).toBe(reverseFilter);
14549  *     });
14550  * ```
14551  *
14552  *
14553  * For more information about how angular filters work, and how to create your own filters, see
14554  * {@link guide/filter Filters} in the Angular Developer Guide.
14555  */
14556
14557 /**
14558  * @ngdoc service
14559  * @name $filter
14560  * @kind function
14561  * @description
14562  * Filters are used for formatting data displayed to the user.
14563  *
14564  * The general syntax in templates is as follows:
14565  *
14566  *         {{ expression [| filter_name[:parameter_value] ... ] }}
14567  *
14568  * @param {String} name Name of the filter function to retrieve
14569  * @return {Function} the filter function
14570  * @example
14571    <example name="$filter" module="filterExample">
14572      <file name="index.html">
14573        <div ng-controller="MainCtrl">
14574         <h3>{{ originalText }}</h3>
14575         <h3>{{ filteredText }}</h3>
14576        </div>
14577      </file>
14578
14579      <file name="script.js">
14580       angular.module('filterExample', [])
14581       .controller('MainCtrl', function($scope, $filter) {
14582         $scope.originalText = 'hello';
14583         $scope.filteredText = $filter('uppercase')($scope.originalText);
14584       });
14585      </file>
14586    </example>
14587   */
14588 $FilterProvider.$inject = ['$provide'];
14589 function $FilterProvider($provide) {
14590   var suffix = 'Filter';
14591
14592   /**
14593    * @ngdoc method
14594    * @name $filterProvider#register
14595    * @param {string|Object} name Name of the filter function, or an object map of filters where
14596    *    the keys are the filter names and the values are the filter factories.
14597    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14598    *    of the registered filter instances.
14599    */
14600   function register(name, factory) {
14601     if(isObject(name)) {
14602       var filters = {};
14603       forEach(name, function(filter, key) {
14604         filters[key] = register(key, filter);
14605       });
14606       return filters;
14607     } else {
14608       return $provide.factory(name + suffix, factory);
14609     }
14610   }
14611   this.register = register;
14612
14613   this.$get = ['$injector', function($injector) {
14614     return function(name) {
14615       return $injector.get(name + suffix);
14616     };
14617   }];
14618
14619   ////////////////////////////////////////
14620
14621   /* global
14622     currencyFilter: false,
14623     dateFilter: false,
14624     filterFilter: false,
14625     jsonFilter: false,
14626     limitToFilter: false,
14627     lowercaseFilter: false,
14628     numberFilter: false,
14629     orderByFilter: false,
14630     uppercaseFilter: false,
14631   */
14632
14633   register('currency', currencyFilter);
14634   register('date', dateFilter);
14635   register('filter', filterFilter);
14636   register('json', jsonFilter);
14637   register('limitTo', limitToFilter);
14638   register('lowercase', lowercaseFilter);
14639   register('number', numberFilter);
14640   register('orderBy', orderByFilter);
14641   register('uppercase', uppercaseFilter);
14642 }
14643
14644 /**
14645  * @ngdoc filter
14646  * @name filter
14647  * @kind function
14648  *
14649  * @description
14650  * Selects a subset of items from `array` and returns it as a new array.
14651  *
14652  * @param {Array} array The source array.
14653  * @param {string|Object|function()} expression The predicate to be used for selecting items from
14654  *   `array`.
14655  *
14656  *   Can be one of:
14657  *
14658  *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14659  *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14660  *     will be returned. The predicate can be negated by prefixing the string with `!`.
14661  *
14662  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14663  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14664  *     which have property `name` containing "M" and property `phone` containing "1". A special
14665  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14666  *     property of the object. That's equivalent to the simple substring match with a `string`
14667  *     as described above. The predicate can be negated by prefixing the string with `!`.
14668  *     For Example `{name: "!M"}` predicate will return an array of items which have property `name`
14669  *     not containing "M".
14670  *
14671  *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14672  *     called for each element of `array`. The final result is an array of those elements that
14673  *     the predicate returned true for.
14674  *
14675  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14676  *     determining if the expected value (from the filter expression) and actual value (from
14677  *     the object in the array) should be considered a match.
14678  *
14679  *   Can be one of:
14680  *
14681  *   - `function(actual, expected)`:
14682  *     The function will be given the object value and the predicate value to compare and
14683  *     should return true if the item should be included in filtered result.
14684  *
14685  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14686  *     this is essentially strict comparison of expected and actual.
14687  *
14688  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
14689  *     insensitive way.
14690  *
14691  * @example
14692    <example>
14693      <file name="index.html">
14694        <div ng-init="friends = [{name:'John', phone:'555-1276'},
14695                                 {name:'Mary', phone:'800-BIG-MARY'},
14696                                 {name:'Mike', phone:'555-4321'},
14697                                 {name:'Adam', phone:'555-5678'},
14698                                 {name:'Julie', phone:'555-8765'},
14699                                 {name:'Juliette', phone:'555-5678'}]"></div>
14700
14701        Search: <input ng-model="searchText">
14702        <table id="searchTextResults">
14703          <tr><th>Name</th><th>Phone</th></tr>
14704          <tr ng-repeat="friend in friends | filter:searchText">
14705            <td>{{friend.name}}</td>
14706            <td>{{friend.phone}}</td>
14707          </tr>
14708        </table>
14709        <hr>
14710        Any: <input ng-model="search.$"> <br>
14711        Name only <input ng-model="search.name"><br>
14712        Phone only <input ng-model="search.phone"><br>
14713        Equality <input type="checkbox" ng-model="strict"><br>
14714        <table id="searchObjResults">
14715          <tr><th>Name</th><th>Phone</th></tr>
14716          <tr ng-repeat="friendObj in friends | filter:search:strict">
14717            <td>{{friendObj.name}}</td>
14718            <td>{{friendObj.phone}}</td>
14719          </tr>
14720        </table>
14721      </file>
14722      <file name="protractor.js" type="protractor">
14723        var expectFriendNames = function(expectedNames, key) {
14724          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14725            arr.forEach(function(wd, i) {
14726              expect(wd.getText()).toMatch(expectedNames[i]);
14727            });
14728          });
14729        };
14730
14731        it('should search across all fields when filtering with a string', function() {
14732          var searchText = element(by.model('searchText'));
14733          searchText.clear();
14734          searchText.sendKeys('m');
14735          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14736
14737          searchText.clear();
14738          searchText.sendKeys('76');
14739          expectFriendNames(['John', 'Julie'], 'friend');
14740        });
14741
14742        it('should search in specific fields when filtering with a predicate object', function() {
14743          var searchAny = element(by.model('search.$'));
14744          searchAny.clear();
14745          searchAny.sendKeys('i');
14746          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14747        });
14748        it('should use a equal comparison when comparator is true', function() {
14749          var searchName = element(by.model('search.name'));
14750          var strict = element(by.model('strict'));
14751          searchName.clear();
14752          searchName.sendKeys('Julie');
14753          strict.click();
14754          expectFriendNames(['Julie'], 'friendObj');
14755        });
14756      </file>
14757    </example>
14758  */
14759 function filterFilter() {
14760   return function(array, expression, comparator) {
14761     if (!isArray(array)) return array;
14762
14763     var comparatorType = typeof(comparator),
14764         predicates = [];
14765
14766     predicates.check = function(value) {
14767       for (var j = 0; j < predicates.length; j++) {
14768         if(!predicates[j](value)) {
14769           return false;
14770         }
14771       }
14772       return true;
14773     };
14774
14775     if (comparatorType !== 'function') {
14776       if (comparatorType === 'boolean' && comparator) {
14777         comparator = function(obj, text) {
14778           return angular.equals(obj, text);
14779         };
14780       } else {
14781         comparator = function(obj, text) {
14782           if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14783             for (var objKey in obj) {
14784               if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14785                   comparator(obj[objKey], text[objKey])) {
14786                 return true;
14787               }
14788             }
14789             return false;
14790           }
14791           text = (''+text).toLowerCase();
14792           return (''+obj).toLowerCase().indexOf(text) > -1;
14793         };
14794       }
14795     }
14796
14797     var search = function(obj, text){
14798       if (typeof text == 'string' && text.charAt(0) === '!') {
14799         return !search(obj, text.substr(1));
14800       }
14801       switch (typeof obj) {
14802         case "boolean":
14803         case "number":
14804         case "string":
14805           return comparator(obj, text);
14806         case "object":
14807           switch (typeof text) {
14808             case "object":
14809               return comparator(obj, text);
14810             default:
14811               for ( var objKey in obj) {
14812                 if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14813                   return true;
14814                 }
14815               }
14816               break;
14817           }
14818           return false;
14819         case "array":
14820           for ( var i = 0; i < obj.length; i++) {
14821             if (search(obj[i], text)) {
14822               return true;
14823             }
14824           }
14825           return false;
14826         default:
14827           return false;
14828       }
14829     };
14830     switch (typeof expression) {
14831       case "boolean":
14832       case "number":
14833       case "string":
14834         // Set up expression object and fall through
14835         expression = {$:expression};
14836         // jshint -W086
14837       case "object":
14838         // jshint +W086
14839         for (var key in expression) {
14840           (function(path) {
14841             if (typeof expression[path] === 'undefined') return;
14842             predicates.push(function(value) {
14843               return search(path == '$' ? value : (value && value[path]), expression[path]);
14844             });
14845           })(key);
14846         }
14847         break;
14848       case 'function':
14849         predicates.push(expression);
14850         break;
14851       default:
14852         return array;
14853     }
14854     var filtered = [];
14855     for ( var j = 0; j < array.length; j++) {
14856       var value = array[j];
14857       if (predicates.check(value)) {
14858         filtered.push(value);
14859       }
14860     }
14861     return filtered;
14862   };
14863 }
14864
14865 /**
14866  * @ngdoc filter
14867  * @name currency
14868  * @kind function
14869  *
14870  * @description
14871  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14872  * symbol for current locale is used.
14873  *
14874  * @param {number} amount Input to filter.
14875  * @param {string=} symbol Currency symbol or identifier to be displayed.
14876  * @returns {string} Formatted number.
14877  *
14878  *
14879  * @example
14880    <example module="currencyExample">
14881      <file name="index.html">
14882        <script>
14883          angular.module('currencyExample', [])
14884            .controller('ExampleController', ['$scope', function($scope) {
14885              $scope.amount = 1234.56;
14886            }]);
14887        </script>
14888        <div ng-controller="ExampleController">
14889          <input type="number" ng-model="amount"> <br>
14890          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14891          custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14892        </div>
14893      </file>
14894      <file name="protractor.js" type="protractor">
14895        it('should init with 1234.56', function() {
14896          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14897          expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14898        });
14899        it('should update', function() {
14900          if (browser.params.browser == 'safari') {
14901            // Safari does not understand the minus key. See
14902            // https://github.com/angular/protractor/issues/481
14903            return;
14904          }
14905          element(by.model('amount')).clear();
14906          element(by.model('amount')).sendKeys('-1234');
14907          expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14908          expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14909        });
14910      </file>
14911    </example>
14912  */
14913 currencyFilter.$inject = ['$locale'];
14914 function currencyFilter($locale) {
14915   var formats = $locale.NUMBER_FORMATS;
14916   return function(amount, currencySymbol){
14917     if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14918     return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14919                 replace(/\u00A4/g, currencySymbol);
14920   };
14921 }
14922
14923 /**
14924  * @ngdoc filter
14925  * @name number
14926  * @kind function
14927  *
14928  * @description
14929  * Formats a number as text.
14930  *
14931  * If the input is not a number an empty string is returned.
14932  *
14933  * @param {number|string} number Number to format.
14934  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14935  * If this is not provided then the fraction size is computed from the current locale's number
14936  * formatting pattern. In the case of the default locale, it will be 3.
14937  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14938  *
14939  * @example
14940    <example module="numberFilterExample">
14941      <file name="index.html">
14942        <script>
14943          angular.module('numberFilterExample', [])
14944            .controller('ExampleController', ['$scope', function($scope) {
14945              $scope.val = 1234.56789;
14946            }]);
14947        </script>
14948        <div ng-controller="ExampleController">
14949          Enter number: <input ng-model='val'><br>
14950          Default formatting: <span id='number-default'>{{val | number}}</span><br>
14951          No fractions: <span>{{val | number:0}}</span><br>
14952          Negative number: <span>{{-val | number:4}}</span>
14953        </div>
14954      </file>
14955      <file name="protractor.js" type="protractor">
14956        it('should format numbers', function() {
14957          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14958          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14959          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14960        });
14961
14962        it('should update', function() {
14963          element(by.model('val')).clear();
14964          element(by.model('val')).sendKeys('3374.333');
14965          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14966          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14967          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14968       });
14969      </file>
14970    </example>
14971  */
14972
14973
14974 numberFilter.$inject = ['$locale'];
14975 function numberFilter($locale) {
14976   var formats = $locale.NUMBER_FORMATS;
14977   return function(number, fractionSize) {
14978     return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14979       fractionSize);
14980   };
14981 }
14982
14983 var DECIMAL_SEP = '.';
14984 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14985   if (number == null || !isFinite(number) || isObject(number)) return '';
14986
14987   var isNegative = number < 0;
14988   number = Math.abs(number);
14989   var numStr = number + '',
14990       formatedText = '',
14991       parts = [];
14992
14993   var hasExponent = false;
14994   if (numStr.indexOf('e') !== -1) {
14995     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14996     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14997       numStr = '0';
14998       number = 0;
14999     } else {
15000       formatedText = numStr;
15001       hasExponent = true;
15002     }
15003   }
15004
15005   if (!hasExponent) {
15006     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
15007
15008     // determine fractionSize if it is not specified
15009     if (isUndefined(fractionSize)) {
15010       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
15011     }
15012
15013     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
15014     // inspired by:
15015     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
15016     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
15017
15018     if (number === 0) {
15019       isNegative = false;
15020     }
15021
15022     var fraction = ('' + number).split(DECIMAL_SEP);
15023     var whole = fraction[0];
15024     fraction = fraction[1] || '';
15025
15026     var i, pos = 0,
15027         lgroup = pattern.lgSize,
15028         group = pattern.gSize;
15029
15030     if (whole.length >= (lgroup + group)) {
15031       pos = whole.length - lgroup;
15032       for (i = 0; i < pos; i++) {
15033         if ((pos - i)%group === 0 && i !== 0) {
15034           formatedText += groupSep;
15035         }
15036         formatedText += whole.charAt(i);
15037       }
15038     }
15039
15040     for (i = pos; i < whole.length; i++) {
15041       if ((whole.length - i)%lgroup === 0 && i !== 0) {
15042         formatedText += groupSep;
15043       }
15044       formatedText += whole.charAt(i);
15045     }
15046
15047     // format fraction part.
15048     while(fraction.length < fractionSize) {
15049       fraction += '0';
15050     }
15051
15052     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
15053   } else {
15054
15055     if (fractionSize > 0 && number > -1 && number < 1) {
15056       formatedText = number.toFixed(fractionSize);
15057     }
15058   }
15059
15060   parts.push(isNegative ? pattern.negPre : pattern.posPre);
15061   parts.push(formatedText);
15062   parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
15063   return parts.join('');
15064 }
15065
15066 function padNumber(num, digits, trim) {
15067   var neg = '';
15068   if (num < 0) {
15069     neg =  '-';
15070     num = -num;
15071   }
15072   num = '' + num;
15073   while(num.length < digits) num = '0' + num;
15074   if (trim)
15075     num = num.substr(num.length - digits);
15076   return neg + num;
15077 }
15078
15079
15080 function dateGetter(name, size, offset, trim) {
15081   offset = offset || 0;
15082   return function(date) {
15083     var value = date['get' + name]();
15084     if (offset > 0 || value > -offset)
15085       value += offset;
15086     if (value === 0 && offset == -12 ) value = 12;
15087     return padNumber(value, size, trim);
15088   };
15089 }
15090
15091 function dateStrGetter(name, shortForm) {
15092   return function(date, formats) {
15093     var value = date['get' + name]();
15094     var get = uppercase(shortForm ? ('SHORT' + name) : name);
15095
15096     return formats[get][value];
15097   };
15098 }
15099
15100 function timeZoneGetter(date) {
15101   var zone = -1 * date.getTimezoneOffset();
15102   var paddedZone = (zone >= 0) ? "+" : "";
15103
15104   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
15105                 padNumber(Math.abs(zone % 60), 2);
15106
15107   return paddedZone;
15108 }
15109
15110 function ampmGetter(date, formats) {
15111   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
15112 }
15113
15114 var DATE_FORMATS = {
15115   yyyy: dateGetter('FullYear', 4),
15116     yy: dateGetter('FullYear', 2, 0, true),
15117      y: dateGetter('FullYear', 1),
15118   MMMM: dateStrGetter('Month'),
15119    MMM: dateStrGetter('Month', true),
15120     MM: dateGetter('Month', 2, 1),
15121      M: dateGetter('Month', 1, 1),
15122     dd: dateGetter('Date', 2),
15123      d: dateGetter('Date', 1),
15124     HH: dateGetter('Hours', 2),
15125      H: dateGetter('Hours', 1),
15126     hh: dateGetter('Hours', 2, -12),
15127      h: dateGetter('Hours', 1, -12),
15128     mm: dateGetter('Minutes', 2),
15129      m: dateGetter('Minutes', 1),
15130     ss: dateGetter('Seconds', 2),
15131      s: dateGetter('Seconds', 1),
15132      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
15133      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
15134    sss: dateGetter('Milliseconds', 3),
15135   EEEE: dateStrGetter('Day'),
15136    EEE: dateStrGetter('Day', true),
15137      a: ampmGetter,
15138      Z: timeZoneGetter
15139 };
15140
15141 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
15142     NUMBER_STRING = /^\-?\d+$/;
15143
15144 /**
15145  * @ngdoc filter
15146  * @name date
15147  * @kind function
15148  *
15149  * @description
15150  *   Formats `date` to a string based on the requested `format`.
15151  *
15152  *   `format` string can be composed of the following elements:
15153  *
15154  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
15155  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
15156  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
15157  *   * `'MMMM'`: Month in year (January-December)
15158  *   * `'MMM'`: Month in year (Jan-Dec)
15159  *   * `'MM'`: Month in year, padded (01-12)
15160  *   * `'M'`: Month in year (1-12)
15161  *   * `'dd'`: Day in month, padded (01-31)
15162  *   * `'d'`: Day in month (1-31)
15163  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
15164  *   * `'EEE'`: Day in Week, (Sun-Sat)
15165  *   * `'HH'`: Hour in day, padded (00-23)
15166  *   * `'H'`: Hour in day (0-23)
15167  *   * `'hh'`: Hour in am/pm, padded (01-12)
15168  *   * `'h'`: Hour in am/pm, (1-12)
15169  *   * `'mm'`: Minute in hour, padded (00-59)
15170  *   * `'m'`: Minute in hour (0-59)
15171  *   * `'ss'`: Second in minute, padded (00-59)
15172  *   * `'s'`: Second in minute (0-59)
15173  *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
15174  *   * `'a'`: am/pm marker
15175  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
15176  *
15177  *   `format` string can also be one of the following predefined
15178  *   {@link guide/i18n localizable formats}:
15179  *
15180  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
15181  *     (e.g. Sep 3, 2010 12:05:08 pm)
15182  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
15183  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
15184  *     (e.g. Friday, September 3, 2010)
15185  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
15186  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
15187  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
15188  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
15189  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
15190  *
15191  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
15192  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
15193  *   (e.g. `"h 'o''clock'"`).
15194  *
15195  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
15196  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
15197  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
15198  *    specified in the string input, the time is considered to be in the local timezone.
15199  * @param {string=} format Formatting rules (see Description). If not specified,
15200  *    `mediumDate` is used.
15201  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
15202  *
15203  * @example
15204    <example>
15205      <file name="index.html">
15206        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
15207            <span>{{1288323623006 | date:'medium'}}</span><br>
15208        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
15209           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15210        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15211           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15212        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
15213           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
15214      </file>
15215      <file name="protractor.js" type="protractor">
15216        it('should format date', function() {
15217          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
15218             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
15219          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
15220             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15221          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15222             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15223          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
15224             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
15225        });
15226      </file>
15227    </example>
15228  */
15229 dateFilter.$inject = ['$locale'];
15230 function dateFilter($locale) {
15231
15232
15233   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
15234                      // 1        2       3         4          5          6          7          8  9     10      11
15235   function jsonStringToDate(string) {
15236     var match;
15237     if (match = string.match(R_ISO8601_STR)) {
15238       var date = new Date(0),
15239           tzHour = 0,
15240           tzMin  = 0,
15241           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
15242           timeSetter = match[8] ? date.setUTCHours : date.setHours;
15243
15244       if (match[9]) {
15245         tzHour = int(match[9] + match[10]);
15246         tzMin = int(match[9] + match[11]);
15247       }
15248       dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
15249       var h = int(match[4]||0) - tzHour;
15250       var m = int(match[5]||0) - tzMin;
15251       var s = int(match[6]||0);
15252       var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
15253       timeSetter.call(date, h, m, s, ms);
15254       return date;
15255     }
15256     return string;
15257   }
15258
15259
15260   return function(date, format) {
15261     var text = '',
15262         parts = [],
15263         fn, match;
15264
15265     format = format || 'mediumDate';
15266     format = $locale.DATETIME_FORMATS[format] || format;
15267     if (isString(date)) {
15268       date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
15269     }
15270
15271     if (isNumber(date)) {
15272       date = new Date(date);
15273     }
15274
15275     if (!isDate(date)) {
15276       return date;
15277     }
15278
15279     while(format) {
15280       match = DATE_FORMATS_SPLIT.exec(format);
15281       if (match) {
15282         parts = concat(parts, match, 1);
15283         format = parts.pop();
15284       } else {
15285         parts.push(format);
15286         format = null;
15287       }
15288     }
15289
15290     forEach(parts, function(value){
15291       fn = DATE_FORMATS[value];
15292       text += fn ? fn(date, $locale.DATETIME_FORMATS)
15293                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
15294     });
15295
15296     return text;
15297   };
15298 }
15299
15300
15301 /**
15302  * @ngdoc filter
15303  * @name json
15304  * @kind function
15305  *
15306  * @description
15307  *   Allows you to convert a JavaScript object into JSON string.
15308  *
15309  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
15310  *   the binding is automatically converted to JSON.
15311  *
15312  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
15313  * @returns {string} JSON string.
15314  *
15315  *
15316  * @example
15317    <example>
15318      <file name="index.html">
15319        <pre>{{ {'name':'value'} | json }}</pre>
15320      </file>
15321      <file name="protractor.js" type="protractor">
15322        it('should jsonify filtered objects', function() {
15323          expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15324        });
15325      </file>
15326    </example>
15327  *
15328  */
15329 function jsonFilter() {
15330   return function(object) {
15331     return toJson(object, true);
15332   };
15333 }
15334
15335
15336 /**
15337  * @ngdoc filter
15338  * @name lowercase
15339  * @kind function
15340  * @description
15341  * Converts string to lowercase.
15342  * @see angular.lowercase
15343  */
15344 var lowercaseFilter = valueFn(lowercase);
15345
15346
15347 /**
15348  * @ngdoc filter
15349  * @name uppercase
15350  * @kind function
15351  * @description
15352  * Converts string to uppercase.
15353  * @see angular.uppercase
15354  */
15355 var uppercaseFilter = valueFn(uppercase);
15356
15357 /**
15358  * @ngdoc filter
15359  * @name limitTo
15360  * @kind function
15361  *
15362  * @description
15363  * Creates a new array or string containing only a specified number of elements. The elements
15364  * are taken from either the beginning or the end of the source array or string, as specified by
15365  * the value and sign (positive or negative) of `limit`.
15366  *
15367  * @param {Array|string} input Source array or string to be limited.
15368  * @param {string|number} limit The length of the returned array or string. If the `limit` number
15369  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15370  *     If the number is negative, `limit` number  of items from the end of the source array/string
15371  *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15372  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15373  *     had less than `limit` elements.
15374  *
15375  * @example
15376    <example module="limitToExample">
15377      <file name="index.html">
15378        <script>
15379          angular.module('limitToExample', [])
15380            .controller('ExampleController', ['$scope', function($scope) {
15381              $scope.numbers = [1,2,3,4,5,6,7,8,9];
15382              $scope.letters = "abcdefghi";
15383              $scope.numLimit = 3;
15384              $scope.letterLimit = 3;
15385            }]);
15386        </script>
15387        <div ng-controller="ExampleController">
15388          Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
15389          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15390          Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
15391          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15392        </div>
15393      </file>
15394      <file name="protractor.js" type="protractor">
15395        var numLimitInput = element(by.model('numLimit'));
15396        var letterLimitInput = element(by.model('letterLimit'));
15397        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15398        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15399
15400        it('should limit the number array to first three items', function() {
15401          expect(numLimitInput.getAttribute('value')).toBe('3');
15402          expect(letterLimitInput.getAttribute('value')).toBe('3');
15403          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15404          expect(limitedLetters.getText()).toEqual('Output letters: abc');
15405        });
15406
15407        it('should update the output when -3 is entered', function() {
15408          numLimitInput.clear();
15409          numLimitInput.sendKeys('-3');
15410          letterLimitInput.clear();
15411          letterLimitInput.sendKeys('-3');
15412          expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15413          expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15414        });
15415
15416        it('should not exceed the maximum size of input array', function() {
15417          numLimitInput.clear();
15418          numLimitInput.sendKeys('100');
15419          letterLimitInput.clear();
15420          letterLimitInput.sendKeys('100');
15421          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15422          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15423        });
15424      </file>
15425    </example>
15426  */
15427 function limitToFilter(){
15428   return function(input, limit) {
15429     if (!isArray(input) && !isString(input)) return input;
15430
15431     if (Math.abs(Number(limit)) === Infinity) {
15432       limit = Number(limit);
15433     } else {
15434       limit = int(limit);
15435     }
15436
15437     if (isString(input)) {
15438       //NaN check on limit
15439       if (limit) {
15440         return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
15441       } else {
15442         return "";
15443       }
15444     }
15445
15446     var out = [],
15447       i, n;
15448
15449     // if abs(limit) exceeds maximum length, trim it
15450     if (limit > input.length)
15451       limit = input.length;
15452     else if (limit < -input.length)
15453       limit = -input.length;
15454
15455     if (limit > 0) {
15456       i = 0;
15457       n = limit;
15458     } else {
15459       i = input.length + limit;
15460       n = input.length;
15461     }
15462
15463     for (; i<n; i++) {
15464       out.push(input[i]);
15465     }
15466
15467     return out;
15468   };
15469 }
15470
15471 /**
15472  * @ngdoc filter
15473  * @name orderBy
15474  * @kind function
15475  *
15476  * @description
15477  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
15478  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
15479  * correctly, make sure they are actually being saved as numbers and not strings.
15480  *
15481  * @param {Array} array The array to sort.
15482  * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
15483  *    used by the comparator to determine the order of elements.
15484  *
15485  *    Can be one of:
15486  *
15487  *    - `function`: Getter function. The result of this function will be sorted using the
15488  *      `<`, `=`, `>` operator.
15489  *    - `string`: An Angular expression. The result of this expression is used to compare elements
15490  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
15491  *      3 first characters of a property called `name`). The result of a constant expression
15492  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
15493  *      to sort object by the value of their `special name` property). An expression can be
15494  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
15495  *      (for example, `+name` or `-name`).
15496  *    - `Array`: An array of function or string predicates. The first predicate in the array
15497  *      is used for sorting, but when two items are equivalent, the next predicate is used.
15498  *
15499  * @param {boolean=} reverse Reverse the order of the array.
15500  * @returns {Array} Sorted copy of the source array.
15501  *
15502  * @example
15503    <example module="orderByExample">
15504      <file name="index.html">
15505        <script>
15506          angular.module('orderByExample', [])
15507            .controller('ExampleController', ['$scope', function($scope) {
15508              $scope.friends =
15509                  [{name:'John', phone:'555-1212', age:10},
15510                   {name:'Mary', phone:'555-9876', age:19},
15511                   {name:'Mike', phone:'555-4321', age:21},
15512                   {name:'Adam', phone:'555-5678', age:35},
15513                   {name:'Julie', phone:'555-8765', age:29}];
15514              $scope.predicate = '-age';
15515            }]);
15516        </script>
15517        <div ng-controller="ExampleController">
15518          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15519          <hr/>
15520          [ <a href="" ng-click="predicate=''">unsorted</a> ]
15521          <table class="friend">
15522            <tr>
15523              <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15524                  (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15525              <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15526              <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15527            </tr>
15528            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15529              <td>{{friend.name}}</td>
15530              <td>{{friend.phone}}</td>
15531              <td>{{friend.age}}</td>
15532            </tr>
15533          </table>
15534        </div>
15535      </file>
15536    </example>
15537  *
15538  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
15539  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
15540  * desired parameters.
15541  *
15542  * Example:
15543  *
15544  * @example
15545   <example module="orderByExample">
15546     <file name="index.html">
15547       <div ng-controller="ExampleController">
15548         <table class="friend">
15549           <tr>
15550             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
15551               (<a href="" ng-click="order('-name',false)">^</a>)</th>
15552             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
15553             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
15554           </tr>
15555           <tr ng-repeat="friend in friends">
15556             <td>{{friend.name}}</td>
15557             <td>{{friend.phone}}</td>
15558             <td>{{friend.age}}</td>
15559           </tr>
15560         </table>
15561       </div>
15562     </file>
15563
15564     <file name="script.js">
15565       angular.module('orderByExample', [])
15566         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
15567           var orderBy = $filter('orderBy');
15568           $scope.friends = [
15569             { name: 'John',    phone: '555-1212',    age: 10 },
15570             { name: 'Mary',    phone: '555-9876',    age: 19 },
15571             { name: 'Mike',    phone: '555-4321',    age: 21 },
15572             { name: 'Adam',    phone: '555-5678',    age: 35 },
15573             { name: 'Julie',   phone: '555-8765',    age: 29 }
15574           ];
15575           $scope.order = function(predicate, reverse) {
15576             $scope.friends = orderBy($scope.friends, predicate, reverse);
15577           };
15578           $scope.order('-age',false);
15579         }]);
15580     </file>
15581 </example>
15582  */
15583 orderByFilter.$inject = ['$parse'];
15584 function orderByFilter($parse){
15585   return function(array, sortPredicate, reverseOrder) {
15586     if (!(isArrayLike(array))) return array;
15587     if (!sortPredicate) return array;
15588     sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15589     sortPredicate = map(sortPredicate, function(predicate){
15590       var descending = false, get = predicate || identity;
15591       if (isString(predicate)) {
15592         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15593           descending = predicate.charAt(0) == '-';
15594           predicate = predicate.substring(1);
15595         }
15596         get = $parse(predicate);
15597         if (get.constant) {
15598           var key = get();
15599           return reverseComparator(function(a,b) {
15600             return compare(a[key], b[key]);
15601           }, descending);
15602         }
15603       }
15604       return reverseComparator(function(a,b){
15605         return compare(get(a),get(b));
15606       }, descending);
15607     });
15608     var arrayCopy = [];
15609     for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
15610     return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
15611
15612     function comparator(o1, o2){
15613       for ( var i = 0; i < sortPredicate.length; i++) {
15614         var comp = sortPredicate[i](o1, o2);
15615         if (comp !== 0) return comp;
15616       }
15617       return 0;
15618     }
15619     function reverseComparator(comp, descending) {
15620       return toBoolean(descending)
15621           ? function(a,b){return comp(b,a);}
15622           : comp;
15623     }
15624     function compare(v1, v2){
15625       var t1 = typeof v1;
15626       var t2 = typeof v2;
15627       if (t1 == t2) {
15628         if (isDate(v1) && isDate(v2)) {
15629           v1 = v1.valueOf();
15630           v2 = v2.valueOf();
15631         }
15632         if (t1 == "string") {
15633            v1 = v1.toLowerCase();
15634            v2 = v2.toLowerCase();
15635         }
15636         if (v1 === v2) return 0;
15637         return v1 < v2 ? -1 : 1;
15638       } else {
15639         return t1 < t2 ? -1 : 1;
15640       }
15641     }
15642   };
15643 }
15644
15645 function ngDirective(directive) {
15646   if (isFunction(directive)) {
15647     directive = {
15648       link: directive
15649     };
15650   }
15651   directive.restrict = directive.restrict || 'AC';
15652   return valueFn(directive);
15653 }
15654
15655 /**
15656  * @ngdoc directive
15657  * @name a
15658  * @restrict E
15659  *
15660  * @description
15661  * Modifies the default behavior of the html A tag so that the default action is prevented when
15662  * the href attribute is empty.
15663  *
15664  * This change permits the easy creation of action links with the `ngClick` directive
15665  * without changing the location or causing page reloads, e.g.:
15666  * `<a href="" ng-click="list.addItem()">Add Item</a>`
15667  */
15668 var htmlAnchorDirective = valueFn({
15669   restrict: 'E',
15670   compile: function(element, attr) {
15671
15672     if (msie <= 8) {
15673
15674       // turn <a href ng-click="..">link</a> into a stylable link in IE
15675       // but only if it doesn't have name attribute, in which case it's an anchor
15676       if (!attr.href && !attr.name) {
15677         attr.$set('href', '');
15678       }
15679
15680       // add a comment node to anchors to workaround IE bug that causes element content to be reset
15681       // to new attribute content if attribute is updated with value containing @ and element also
15682       // contains value with @
15683       // see issue #1949
15684       element.append(document.createComment('IE fix'));
15685     }
15686
15687     if (!attr.href && !attr.xlinkHref && !attr.name) {
15688       return function(scope, element) {
15689         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15690         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15691                    'xlink:href' : 'href';
15692         element.on('click', function(event){
15693           // if we have no href url, then don't navigate anywhere.
15694           if (!element.attr(href)) {
15695             event.preventDefault();
15696           }
15697         });
15698       };
15699     }
15700   }
15701 });
15702
15703 /**
15704  * @ngdoc directive
15705  * @name ngHref
15706  * @restrict A
15707  * @priority 99
15708  *
15709  * @description
15710  * Using Angular markup like `{{hash}}` in an href attribute will
15711  * make the link go to the wrong URL if the user clicks it before
15712  * Angular has a chance to replace the `{{hash}}` markup with its
15713  * value. Until Angular replaces the markup the link will be broken
15714  * and will most likely return a 404 error.
15715  *
15716  * The `ngHref` directive solves this problem.
15717  *
15718  * The wrong way to write it:
15719  * ```html
15720  * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15721  * ```
15722  *
15723  * The correct way to write it:
15724  * ```html
15725  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15726  * ```
15727  *
15728  * @element A
15729  * @param {template} ngHref any string which can contain `{{}}` markup.
15730  *
15731  * @example
15732  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15733  * in links and their different behaviors:
15734     <example>
15735       <file name="index.html">
15736         <input ng-model="value" /><br />
15737         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15738         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15739         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15740         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15741         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15742         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15743       </file>
15744       <file name="protractor.js" type="protractor">
15745         it('should execute ng-click but not reload when href without value', function() {
15746           element(by.id('link-1')).click();
15747           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15748           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15749         });
15750
15751         it('should execute ng-click but not reload when href empty string', function() {
15752           element(by.id('link-2')).click();
15753           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15754           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15755         });
15756
15757         it('should execute ng-click and change url when ng-href specified', function() {
15758           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15759
15760           element(by.id('link-3')).click();
15761
15762           // At this point, we navigate away from an Angular page, so we need
15763           // to use browser.driver to get the base webdriver.
15764
15765           browser.wait(function() {
15766             return browser.driver.getCurrentUrl().then(function(url) {
15767               return url.match(/\/123$/);
15768             });
15769           }, 5000, 'page should navigate to /123');
15770         });
15771
15772         xit('should execute ng-click but not reload when href empty string and name specified', function() {
15773           element(by.id('link-4')).click();
15774           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15775           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15776         });
15777
15778         it('should execute ng-click but not reload when no href but name specified', function() {
15779           element(by.id('link-5')).click();
15780           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15781           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15782         });
15783
15784         it('should only change url when only ng-href', function() {
15785           element(by.model('value')).clear();
15786           element(by.model('value')).sendKeys('6');
15787           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15788
15789           element(by.id('link-6')).click();
15790
15791           // At this point, we navigate away from an Angular page, so we need
15792           // to use browser.driver to get the base webdriver.
15793           browser.wait(function() {
15794             return browser.driver.getCurrentUrl().then(function(url) {
15795               return url.match(/\/6$/);
15796             });
15797           }, 5000, 'page should navigate to /6');
15798         });
15799       </file>
15800     </example>
15801  */
15802
15803 /**
15804  * @ngdoc directive
15805  * @name ngSrc
15806  * @restrict A
15807  * @priority 99
15808  *
15809  * @description
15810  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15811  * work right: The browser will fetch from the URL with the literal
15812  * text `{{hash}}` until Angular replaces the expression inside
15813  * `{{hash}}`. The `ngSrc` directive solves this problem.
15814  *
15815  * The buggy way to write it:
15816  * ```html
15817  * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15818  * ```
15819  *
15820  * The correct way to write it:
15821  * ```html
15822  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15823  * ```
15824  *
15825  * @element IMG
15826  * @param {template} ngSrc any string which can contain `{{}}` markup.
15827  */
15828
15829 /**
15830  * @ngdoc directive
15831  * @name ngSrcset
15832  * @restrict A
15833  * @priority 99
15834  *
15835  * @description
15836  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15837  * work right: The browser will fetch from the URL with the literal
15838  * text `{{hash}}` until Angular replaces the expression inside
15839  * `{{hash}}`. The `ngSrcset` directive solves this problem.
15840  *
15841  * The buggy way to write it:
15842  * ```html
15843  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15844  * ```
15845  *
15846  * The correct way to write it:
15847  * ```html
15848  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15849  * ```
15850  *
15851  * @element IMG
15852  * @param {template} ngSrcset any string which can contain `{{}}` markup.
15853  */
15854
15855 /**
15856  * @ngdoc directive
15857  * @name ngDisabled
15858  * @restrict A
15859  * @priority 100
15860  *
15861  * @description
15862  *
15863  * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15864  * ```html
15865  * <div ng-init="scope = { isDisabled: false }">
15866  *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15867  * </div>
15868  * ```
15869  *
15870  * The HTML specification does not require browsers to preserve the values of boolean attributes
15871  * such as disabled. (Their presence means true and their absence means false.)
15872  * If we put an Angular interpolation expression into such an attribute then the
15873  * binding information would be lost when the browser removes the attribute.
15874  * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15875  * This complementary directive is not removed by the browser and so provides
15876  * a permanent reliable place to store the binding information.
15877  *
15878  * @example
15879     <example>
15880       <file name="index.html">
15881         Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15882         <button ng-model="button" ng-disabled="checked">Button</button>
15883       </file>
15884       <file name="protractor.js" type="protractor">
15885         it('should toggle button', function() {
15886           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
15887           element(by.model('checked')).click();
15888           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
15889         });
15890       </file>
15891     </example>
15892  *
15893  * @element INPUT
15894  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
15895  *     then special attribute "disabled" will be set on the element
15896  */
15897
15898
15899 /**
15900  * @ngdoc directive
15901  * @name ngChecked
15902  * @restrict A
15903  * @priority 100
15904  *
15905  * @description
15906  * The HTML specification does not require browsers to preserve the values of boolean attributes
15907  * such as checked. (Their presence means true and their absence means false.)
15908  * If we put an Angular interpolation expression into such an attribute then the
15909  * binding information would be lost when the browser removes the attribute.
15910  * The `ngChecked` directive solves this problem for the `checked` attribute.
15911  * This complementary directive is not removed by the browser and so provides
15912  * a permanent reliable place to store the binding information.
15913  * @example
15914     <example>
15915       <file name="index.html">
15916         Check me to check both: <input type="checkbox" ng-model="master"><br/>
15917         <input id="checkSlave" type="checkbox" ng-checked="master">
15918       </file>
15919       <file name="protractor.js" type="protractor">
15920         it('should check both checkBoxes', function() {
15921           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15922           element(by.model('master')).click();
15923           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15924         });
15925       </file>
15926     </example>
15927  *
15928  * @element INPUT
15929  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
15930  *     then special attribute "checked" will be set on the element
15931  */
15932
15933
15934 /**
15935  * @ngdoc directive
15936  * @name ngReadonly
15937  * @restrict A
15938  * @priority 100
15939  *
15940  * @description
15941  * The HTML specification does not require browsers to preserve the values of boolean attributes
15942  * such as readonly. (Their presence means true and their absence means false.)
15943  * If we put an Angular interpolation expression into such an attribute then the
15944  * binding information would be lost when the browser removes the attribute.
15945  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15946  * This complementary directive is not removed by the browser and so provides
15947  * a permanent reliable place to store the binding information.
15948  * @example
15949     <example>
15950       <file name="index.html">
15951         Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15952         <input type="text" ng-readonly="checked" value="I'm Angular"/>
15953       </file>
15954       <file name="protractor.js" type="protractor">
15955         it('should toggle readonly attr', function() {
15956           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
15957           element(by.model('checked')).click();
15958           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
15959         });
15960       </file>
15961     </example>
15962  *
15963  * @element INPUT
15964  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
15965  *     then special attribute "readonly" will be set on the element
15966  */
15967
15968
15969 /**
15970  * @ngdoc directive
15971  * @name ngSelected
15972  * @restrict A
15973  * @priority 100
15974  *
15975  * @description
15976  * The HTML specification does not require browsers to preserve the values of boolean attributes
15977  * such as selected. (Their presence means true and their absence means false.)
15978  * If we put an Angular interpolation expression into such an attribute then the
15979  * binding information would be lost when the browser removes the attribute.
15980  * The `ngSelected` directive solves this problem for the `selected` attribute.
15981  * This complementary directive is not removed by the browser and so provides
15982  * a permanent reliable place to store the binding information.
15983  *
15984  * @example
15985     <example>
15986       <file name="index.html">
15987         Check me to select: <input type="checkbox" ng-model="selected"><br/>
15988         <select>
15989           <option>Hello!</option>
15990           <option id="greet" ng-selected="selected">Greetings!</option>
15991         </select>
15992       </file>
15993       <file name="protractor.js" type="protractor">
15994         it('should select Greetings!', function() {
15995           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15996           element(by.model('selected')).click();
15997           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15998         });
15999       </file>
16000     </example>
16001  *
16002  * @element OPTION
16003  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
16004  *     then special attribute "selected" will be set on the element
16005  */
16006
16007 /**
16008  * @ngdoc directive
16009  * @name ngOpen
16010  * @restrict A
16011  * @priority 100
16012  *
16013  * @description
16014  * The HTML specification does not require browsers to preserve the values of boolean attributes
16015  * such as open. (Their presence means true and their absence means false.)
16016  * If we put an Angular interpolation expression into such an attribute then the
16017  * binding information would be lost when the browser removes the attribute.
16018  * The `ngOpen` directive solves this problem for the `open` attribute.
16019  * This complementary directive is not removed by the browser and so provides
16020  * a permanent reliable place to store the binding information.
16021  * @example
16022      <example>
16023        <file name="index.html">
16024          Check me check multiple: <input type="checkbox" ng-model="open"><br/>
16025          <details id="details" ng-open="open">
16026             <summary>Show/Hide me</summary>
16027          </details>
16028        </file>
16029        <file name="protractor.js" type="protractor">
16030          it('should toggle open', function() {
16031            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
16032            element(by.model('open')).click();
16033            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
16034          });
16035        </file>
16036      </example>
16037  *
16038  * @element DETAILS
16039  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
16040  *     then special attribute "open" will be set on the element
16041  */
16042
16043 var ngAttributeAliasDirectives = {};
16044
16045
16046 // boolean attrs are evaluated
16047 forEach(BOOLEAN_ATTR, function(propName, attrName) {
16048   // binding to multiple is not supported
16049   if (propName == "multiple") return;
16050
16051   var normalized = directiveNormalize('ng-' + attrName);
16052   ngAttributeAliasDirectives[normalized] = function() {
16053     return {
16054       priority: 100,
16055       link: function(scope, element, attr) {
16056         scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
16057           attr.$set(attrName, !!value);
16058         });
16059       }
16060     };
16061   };
16062 });
16063
16064
16065 // ng-src, ng-srcset, ng-href are interpolated
16066 forEach(['src', 'srcset', 'href'], function(attrName) {
16067   var normalized = directiveNormalize('ng-' + attrName);
16068   ngAttributeAliasDirectives[normalized] = function() {
16069     return {
16070       priority: 99, // it needs to run after the attributes are interpolated
16071       link: function(scope, element, attr) {
16072         var propName = attrName,
16073             name = attrName;
16074
16075         if (attrName === 'href' &&
16076             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
16077           name = 'xlinkHref';
16078           attr.$attr[name] = 'xlink:href';
16079           propName = null;
16080         }
16081
16082         attr.$observe(normalized, function(value) {
16083           if (!value) {
16084             if (attrName === 'href') {
16085               attr.$set(name, null);
16086             }
16087             return;
16088           }
16089
16090           attr.$set(name, value);
16091
16092           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
16093           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
16094           // to set the property as well to achieve the desired effect.
16095           // we use attr[attrName] value since $set can sanitize the url.
16096           if (msie && propName) element.prop(propName, attr[name]);
16097         });
16098       }
16099     };
16100   };
16101 });
16102
16103 /* global -nullFormCtrl */
16104 var nullFormCtrl = {
16105   $addControl: noop,
16106   $removeControl: noop,
16107   $setValidity: noop,
16108   $setDirty: noop,
16109   $setPristine: noop
16110 };
16111
16112 /**
16113  * @ngdoc type
16114  * @name form.FormController
16115  *
16116  * @property {boolean} $pristine True if user has not interacted with the form yet.
16117  * @property {boolean} $dirty True if user has already interacted with the form.
16118  * @property {boolean} $valid True if all of the containing forms and controls are valid.
16119  * @property {boolean} $invalid True if at least one containing control or form is invalid.
16120  *
16121  * @property {Object} $error Is an object hash, containing references to all invalid controls or
16122  *  forms, where:
16123  *
16124  *  - keys are validation tokens (error names),
16125  *  - values are arrays of controls or forms that are invalid for given error name.
16126  *
16127  *
16128  *  Built-in validation tokens:
16129  *
16130  *  - `email`
16131  *  - `max`
16132  *  - `maxlength`
16133  *  - `min`
16134  *  - `minlength`
16135  *  - `number`
16136  *  - `pattern`
16137  *  - `required`
16138  *  - `url`
16139  *
16140  * @description
16141  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
16142  * such as being valid/invalid or dirty/pristine.
16143  *
16144  * Each {@link ng.directive:form form} directive creates an instance
16145  * of `FormController`.
16146  *
16147  */
16148 //asks for $scope to fool the BC controller module
16149 FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
16150 function FormController(element, attrs, $scope, $animate) {
16151   var form = this,
16152       parentForm = element.parent().controller('form') || nullFormCtrl,
16153       invalidCount = 0, // used to easily determine if we are valid
16154       errors = form.$error = {},
16155       controls = [];
16156
16157   // init state
16158   form.$name = attrs.name || attrs.ngForm;
16159   form.$dirty = false;
16160   form.$pristine = true;
16161   form.$valid = true;
16162   form.$invalid = false;
16163
16164   parentForm.$addControl(form);
16165
16166   // Setup initial state of the control
16167   element.addClass(PRISTINE_CLASS);
16168   toggleValidCss(true);
16169
16170   // convenience method for easy toggling of classes
16171   function toggleValidCss(isValid, validationErrorKey) {
16172     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16173     $animate.setClass(element,
16174       (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
16175       (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16176   }
16177
16178   /**
16179    * @ngdoc method
16180    * @name form.FormController#$addControl
16181    *
16182    * @description
16183    * Register a control with the form.
16184    *
16185    * Input elements using ngModelController do this automatically when they are linked.
16186    */
16187   form.$addControl = function(control) {
16188     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
16189     // and not added to the scope.  Now we throw an error.
16190     assertNotHasOwnProperty(control.$name, 'input');
16191     controls.push(control);
16192
16193     if (control.$name) {
16194       form[control.$name] = control;
16195     }
16196   };
16197
16198   /**
16199    * @ngdoc method
16200    * @name form.FormController#$removeControl
16201    *
16202    * @description
16203    * Deregister a control from the form.
16204    *
16205    * Input elements using ngModelController do this automatically when they are destroyed.
16206    */
16207   form.$removeControl = function(control) {
16208     if (control.$name && form[control.$name] === control) {
16209       delete form[control.$name];
16210     }
16211     forEach(errors, function(queue, validationToken) {
16212       form.$setValidity(validationToken, true, control);
16213     });
16214
16215     arrayRemove(controls, control);
16216   };
16217
16218   /**
16219    * @ngdoc method
16220    * @name form.FormController#$setValidity
16221    *
16222    * @description
16223    * Sets the validity of a form control.
16224    *
16225    * This method will also propagate to parent forms.
16226    */
16227   form.$setValidity = function(validationToken, isValid, control) {
16228     var queue = errors[validationToken];
16229
16230     if (isValid) {
16231       if (queue) {
16232         arrayRemove(queue, control);
16233         if (!queue.length) {
16234           invalidCount--;
16235           if (!invalidCount) {
16236             toggleValidCss(isValid);
16237             form.$valid = true;
16238             form.$invalid = false;
16239           }
16240           errors[validationToken] = false;
16241           toggleValidCss(true, validationToken);
16242           parentForm.$setValidity(validationToken, true, form);
16243         }
16244       }
16245
16246     } else {
16247       if (!invalidCount) {
16248         toggleValidCss(isValid);
16249       }
16250       if (queue) {
16251         if (includes(queue, control)) return;
16252       } else {
16253         errors[validationToken] = queue = [];
16254         invalidCount++;
16255         toggleValidCss(false, validationToken);
16256         parentForm.$setValidity(validationToken, false, form);
16257       }
16258       queue.push(control);
16259
16260       form.$valid = false;
16261       form.$invalid = true;
16262     }
16263   };
16264
16265   /**
16266    * @ngdoc method
16267    * @name form.FormController#$setDirty
16268    *
16269    * @description
16270    * Sets the form to a dirty state.
16271    *
16272    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
16273    * state (ng-dirty class). This method will also propagate to parent forms.
16274    */
16275   form.$setDirty = function() {
16276     $animate.removeClass(element, PRISTINE_CLASS);
16277     $animate.addClass(element, DIRTY_CLASS);
16278     form.$dirty = true;
16279     form.$pristine = false;
16280     parentForm.$setDirty();
16281   };
16282
16283   /**
16284    * @ngdoc method
16285    * @name form.FormController#$setPristine
16286    *
16287    * @description
16288    * Sets the form to its pristine state.
16289    *
16290    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
16291    * state (ng-pristine class). This method will also propagate to all the controls contained
16292    * in this form.
16293    *
16294    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
16295    * saving or resetting it.
16296    */
16297   form.$setPristine = function () {
16298     $animate.removeClass(element, DIRTY_CLASS);
16299     $animate.addClass(element, PRISTINE_CLASS);
16300     form.$dirty = false;
16301     form.$pristine = true;
16302     forEach(controls, function(control) {
16303       control.$setPristine();
16304     });
16305   };
16306 }
16307
16308
16309 /**
16310  * @ngdoc directive
16311  * @name ngForm
16312  * @restrict EAC
16313  *
16314  * @description
16315  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
16316  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
16317  * sub-group of controls needs to be determined.
16318  *
16319  * Note: the purpose of `ngForm` is to group controls,
16320  * but not to be a replacement for the `<form>` tag with all of its capabilities
16321  * (e.g. posting to the server, ...).
16322  *
16323  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
16324  *                       related scope, under this name.
16325  *
16326  */
16327
16328  /**
16329  * @ngdoc directive
16330  * @name form
16331  * @restrict E
16332  *
16333  * @description
16334  * Directive that instantiates
16335  * {@link form.FormController FormController}.
16336  *
16337  * If the `name` attribute is specified, the form controller is published onto the current scope under
16338  * this name.
16339  *
16340  * # Alias: {@link ng.directive:ngForm `ngForm`}
16341  *
16342  * In Angular forms can be nested. This means that the outer form is valid when all of the child
16343  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
16344  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
16345  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
16346  * using Angular validation directives in forms that are dynamically generated using the
16347  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
16348  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
16349  * `ngForm` directive and nest these in an outer `form` element.
16350  *
16351  *
16352  * # CSS classes
16353  *  - `ng-valid` is set if the form is valid.
16354  *  - `ng-invalid` is set if the form is invalid.
16355  *  - `ng-pristine` is set if the form is pristine.
16356  *  - `ng-dirty` is set if the form is dirty.
16357  *
16358  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
16359  *
16360  *
16361  * # Submitting a form and preventing the default action
16362  *
16363  * Since the role of forms in client-side Angular applications is different than in classical
16364  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
16365  * page reload that sends the data to the server. Instead some javascript logic should be triggered
16366  * to handle the form submission in an application-specific way.
16367  *
16368  * For this reason, Angular prevents the default action (form submission to the server) unless the
16369  * `<form>` element has an `action` attribute specified.
16370  *
16371  * You can use one of the following two ways to specify what javascript method should be called when
16372  * a form is submitted:
16373  *
16374  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
16375  * - {@link ng.directive:ngClick ngClick} directive on the first
16376   *  button or input field of type submit (input[type=submit])
16377  *
16378  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
16379  * or {@link ng.directive:ngClick ngClick} directives.
16380  * This is because of the following form submission rules in the HTML specification:
16381  *
16382  * - If a form has only one input field then hitting enter in this field triggers form submit
16383  * (`ngSubmit`)
16384  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
16385  * doesn't trigger submit
16386  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16387  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16388  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16389  *
16390  *
16391  * ## Animation Hooks
16392  *
16393  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16394  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16395  * other validations that are performed within the form. Animations in ngForm are similar to how
16396  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16397  * as JS animations.
16398  *
16399  * The following example shows a simple way to utilize CSS transitions to style a form element
16400  * that has been rendered as invalid after it has been validated:
16401  *
16402  * <pre>
16403  * //be sure to include ngAnimate as a module to hook into more
16404  * //advanced animations
16405  * .my-form {
16406  *   transition:0.5s linear all;
16407  *   background: white;
16408  * }
16409  * .my-form.ng-invalid {
16410  *   background: red;
16411  *   color:white;
16412  * }
16413  * </pre>
16414  *
16415  * @example
16416     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
16417       <file name="index.html">
16418        <script>
16419          angular.module('formExample', [])
16420            .controller('FormController', ['$scope', function($scope) {
16421              $scope.userType = 'guest';
16422            }]);
16423        </script>
16424        <style>
16425         .my-form {
16426           -webkit-transition:all linear 0.5s;
16427           transition:all linear 0.5s;
16428           background: transparent;
16429         }
16430         .my-form.ng-invalid {
16431           background: red;
16432         }
16433        </style>
16434        <form name="myForm" ng-controller="FormController" class="my-form">
16435          userType: <input name="input" ng-model="userType" required>
16436          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16437          <tt>userType = {{userType}}</tt><br>
16438          <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16439          <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16440          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16441          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16442         </form>
16443       </file>
16444       <file name="protractor.js" type="protractor">
16445         it('should initialize to model', function() {
16446           var userType = element(by.binding('userType'));
16447           var valid = element(by.binding('myForm.input.$valid'));
16448
16449           expect(userType.getText()).toContain('guest');
16450           expect(valid.getText()).toContain('true');
16451         });
16452
16453         it('should be invalid if empty', function() {
16454           var userType = element(by.binding('userType'));
16455           var valid = element(by.binding('myForm.input.$valid'));
16456           var userInput = element(by.model('userType'));
16457
16458           userInput.clear();
16459           userInput.sendKeys('');
16460
16461           expect(userType.getText()).toEqual('userType =');
16462           expect(valid.getText()).toContain('false');
16463         });
16464       </file>
16465     </example>
16466  *
16467  * @param {string=} name Name of the form. If specified, the form controller will be published into
16468  *                       related scope, under this name.
16469  */
16470 var formDirectiveFactory = function(isNgForm) {
16471   return ['$timeout', function($timeout) {
16472     var formDirective = {
16473       name: 'form',
16474       restrict: isNgForm ? 'EAC' : 'E',
16475       controller: FormController,
16476       compile: function() {
16477         return {
16478           pre: function(scope, formElement, attr, controller) {
16479             if (!attr.action) {
16480               // we can't use jq events because if a form is destroyed during submission the default
16481               // action is not prevented. see #1238
16482               //
16483               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16484               // page reload if the form was destroyed by submission of the form via a click handler
16485               // on a button in the form. Looks like an IE9 specific bug.
16486               var preventDefaultListener = function(event) {
16487                 event.preventDefault
16488                   ? event.preventDefault()
16489                   : event.returnValue = false; // IE
16490               };
16491
16492               addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16493
16494               // unregister the preventDefault listener so that we don't not leak memory but in a
16495               // way that will achieve the prevention of the default action.
16496               formElement.on('$destroy', function() {
16497                 $timeout(function() {
16498                   removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16499                 }, 0, false);
16500               });
16501             }
16502
16503             var parentFormCtrl = formElement.parent().controller('form'),
16504                 alias = attr.name || attr.ngForm;
16505
16506             if (alias) {
16507               setter(scope, alias, controller, alias);
16508             }
16509             if (parentFormCtrl) {
16510               formElement.on('$destroy', function() {
16511                 parentFormCtrl.$removeControl(controller);
16512                 if (alias) {
16513                   setter(scope, alias, undefined, alias);
16514                 }
16515                 extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16516               });
16517             }
16518           }
16519         };
16520       }
16521     };
16522
16523     return formDirective;
16524   }];
16525 };
16526
16527 var formDirective = formDirectiveFactory();
16528 var ngFormDirective = formDirectiveFactory(true);
16529
16530 /* global VALID_CLASS: true,
16531     INVALID_CLASS: true,
16532     PRISTINE_CLASS: true,
16533     DIRTY_CLASS: true
16534 */
16535
16536 var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16537 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;
16538 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16539
16540 var inputType = {
16541
16542   /**
16543    * @ngdoc input
16544    * @name input[text]
16545    *
16546    * @description
16547    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
16548    *
16549    * *NOTE* Not every feature offered is available for all input types.
16550    *
16551    * @param {string} ngModel Assignable angular expression to data-bind to.
16552    * @param {string=} name Property name of the form under which the control is published.
16553    * @param {string=} required Adds `required` validation error key if the value is not entered.
16554    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16555    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16556    *    `required` when you want to data-bind to the `required` attribute.
16557    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16558    *    minlength.
16559    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16560    *    maxlength.
16561    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16562    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16563    *    patterns defined as scope expressions.
16564    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16565    *    interaction with the input element.
16566    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16567    *    This parameter is ignored for input[type=password] controls, which will never trim the
16568    *    input.
16569    *
16570    * @example
16571       <example name="text-input-directive" module="textInputExample">
16572         <file name="index.html">
16573          <script>
16574            angular.module('textInputExample', [])
16575              .controller('ExampleController', ['$scope', function($scope) {
16576                $scope.text = 'guest';
16577                $scope.word = /^\s*\w*\s*$/;
16578              }]);
16579          </script>
16580          <form name="myForm" ng-controller="ExampleController">
16581            Single word: <input type="text" name="input" ng-model="text"
16582                                ng-pattern="word" required ng-trim="false">
16583            <span class="error" ng-show="myForm.input.$error.required">
16584              Required!</span>
16585            <span class="error" ng-show="myForm.input.$error.pattern">
16586              Single word only!</span>
16587
16588            <tt>text = {{text}}</tt><br/>
16589            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16590            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16591            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16592            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16593           </form>
16594         </file>
16595         <file name="protractor.js" type="protractor">
16596           var text = element(by.binding('text'));
16597           var valid = element(by.binding('myForm.input.$valid'));
16598           var input = element(by.model('text'));
16599
16600           it('should initialize to model', function() {
16601             expect(text.getText()).toContain('guest');
16602             expect(valid.getText()).toContain('true');
16603           });
16604
16605           it('should be invalid if empty', function() {
16606             input.clear();
16607             input.sendKeys('');
16608
16609             expect(text.getText()).toEqual('text =');
16610             expect(valid.getText()).toContain('false');
16611           });
16612
16613           it('should be invalid if multi word', function() {
16614             input.clear();
16615             input.sendKeys('hello world');
16616
16617             expect(valid.getText()).toContain('false');
16618           });
16619         </file>
16620       </example>
16621    */
16622   'text': textInputType,
16623
16624
16625   /**
16626    * @ngdoc input
16627    * @name input[number]
16628    *
16629    * @description
16630    * Text input with number validation and transformation. Sets the `number` validation
16631    * error if not a valid number.
16632    *
16633    * @param {string} ngModel Assignable angular expression to data-bind to.
16634    * @param {string=} name Property name of the form under which the control is published.
16635    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16636    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16637    * @param {string=} required Sets `required` validation error key if the value is not entered.
16638    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16639    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16640    *    `required` when you want to data-bind to the `required` attribute.
16641    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16642    *    minlength.
16643    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16644    *    maxlength.
16645    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16646    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16647    *    patterns defined as scope expressions.
16648    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16649    *    interaction with the input element.
16650    *
16651    * @example
16652       <example name="number-input-directive" module="numberExample">
16653         <file name="index.html">
16654          <script>
16655            angular.module('numberExample', [])
16656              .controller('ExampleController', ['$scope', function($scope) {
16657                $scope.value = 12;
16658              }]);
16659          </script>
16660          <form name="myForm" ng-controller="ExampleController">
16661            Number: <input type="number" name="input" ng-model="value"
16662                           min="0" max="99" required>
16663            <span class="error" ng-show="myForm.input.$error.required">
16664              Required!</span>
16665            <span class="error" ng-show="myForm.input.$error.number">
16666              Not valid number!</span>
16667            <tt>value = {{value}}</tt><br/>
16668            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16669            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16670            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16671            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16672           </form>
16673         </file>
16674         <file name="protractor.js" type="protractor">
16675           var value = element(by.binding('value'));
16676           var valid = element(by.binding('myForm.input.$valid'));
16677           var input = element(by.model('value'));
16678
16679           it('should initialize to model', function() {
16680             expect(value.getText()).toContain('12');
16681             expect(valid.getText()).toContain('true');
16682           });
16683
16684           it('should be invalid if empty', function() {
16685             input.clear();
16686             input.sendKeys('');
16687             expect(value.getText()).toEqual('value =');
16688             expect(valid.getText()).toContain('false');
16689           });
16690
16691           it('should be invalid if over max', function() {
16692             input.clear();
16693             input.sendKeys('123');
16694             expect(value.getText()).toEqual('value =');
16695             expect(valid.getText()).toContain('false');
16696           });
16697         </file>
16698       </example>
16699    */
16700   'number': numberInputType,
16701
16702
16703   /**
16704    * @ngdoc input
16705    * @name input[url]
16706    *
16707    * @description
16708    * Text input with URL validation. Sets the `url` validation error key if the content is not a
16709    * valid URL.
16710    *
16711    * @param {string} ngModel Assignable angular expression to data-bind to.
16712    * @param {string=} name Property name of the form under which the control is published.
16713    * @param {string=} required Sets `required` validation error key if the value is not entered.
16714    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16715    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16716    *    `required` when you want to data-bind to the `required` attribute.
16717    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16718    *    minlength.
16719    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16720    *    maxlength.
16721    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16722    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16723    *    patterns defined as scope expressions.
16724    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16725    *    interaction with the input element.
16726    *
16727    * @example
16728       <example name="url-input-directive" module="urlExample">
16729         <file name="index.html">
16730          <script>
16731            angular.module('urlExample', [])
16732              .controller('ExampleController', ['$scope', function($scope) {
16733                $scope.text = 'http://google.com';
16734              }]);
16735          </script>
16736          <form name="myForm" ng-controller="ExampleController">
16737            URL: <input type="url" name="input" ng-model="text" required>
16738            <span class="error" ng-show="myForm.input.$error.required">
16739              Required!</span>
16740            <span class="error" ng-show="myForm.input.$error.url">
16741              Not valid url!</span>
16742            <tt>text = {{text}}</tt><br/>
16743            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16744            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16745            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16746            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16747            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16748           </form>
16749         </file>
16750         <file name="protractor.js" type="protractor">
16751           var text = element(by.binding('text'));
16752           var valid = element(by.binding('myForm.input.$valid'));
16753           var input = element(by.model('text'));
16754
16755           it('should initialize to model', function() {
16756             expect(text.getText()).toContain('http://google.com');
16757             expect(valid.getText()).toContain('true');
16758           });
16759
16760           it('should be invalid if empty', function() {
16761             input.clear();
16762             input.sendKeys('');
16763
16764             expect(text.getText()).toEqual('text =');
16765             expect(valid.getText()).toContain('false');
16766           });
16767
16768           it('should be invalid if not url', function() {
16769             input.clear();
16770             input.sendKeys('box');
16771
16772             expect(valid.getText()).toContain('false');
16773           });
16774         </file>
16775       </example>
16776    */
16777   'url': urlInputType,
16778
16779
16780   /**
16781    * @ngdoc input
16782    * @name input[email]
16783    *
16784    * @description
16785    * Text input with email validation. Sets the `email` validation error key if not a valid email
16786    * address.
16787    *
16788    * @param {string} ngModel Assignable angular expression to data-bind to.
16789    * @param {string=} name Property name of the form under which the control is published.
16790    * @param {string=} required Sets `required` validation error key if the value is not entered.
16791    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16792    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16793    *    `required` when you want to data-bind to the `required` attribute.
16794    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16795    *    minlength.
16796    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16797    *    maxlength.
16798    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16799    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16800    *    patterns defined as scope expressions.
16801    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16802    *    interaction with the input element.
16803    *
16804    * @example
16805       <example name="email-input-directive" module="emailExample">
16806         <file name="index.html">
16807          <script>
16808            angular.module('emailExample', [])
16809              .controller('ExampleController', ['$scope', function($scope) {
16810                $scope.text = 'me@example.com';
16811              }]);
16812          </script>
16813            <form name="myForm" ng-controller="ExampleController">
16814              Email: <input type="email" name="input" ng-model="text" required>
16815              <span class="error" ng-show="myForm.input.$error.required">
16816                Required!</span>
16817              <span class="error" ng-show="myForm.input.$error.email">
16818                Not valid email!</span>
16819              <tt>text = {{text}}</tt><br/>
16820              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16821              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16822              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16823              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16824              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16825            </form>
16826          </file>
16827         <file name="protractor.js" type="protractor">
16828           var text = element(by.binding('text'));
16829           var valid = element(by.binding('myForm.input.$valid'));
16830           var input = element(by.model('text'));
16831
16832           it('should initialize to model', function() {
16833             expect(text.getText()).toContain('me@example.com');
16834             expect(valid.getText()).toContain('true');
16835           });
16836
16837           it('should be invalid if empty', function() {
16838             input.clear();
16839             input.sendKeys('');
16840             expect(text.getText()).toEqual('text =');
16841             expect(valid.getText()).toContain('false');
16842           });
16843
16844           it('should be invalid if not email', function() {
16845             input.clear();
16846             input.sendKeys('xxx');
16847
16848             expect(valid.getText()).toContain('false');
16849           });
16850         </file>
16851       </example>
16852    */
16853   'email': emailInputType,
16854
16855
16856   /**
16857    * @ngdoc input
16858    * @name input[radio]
16859    *
16860    * @description
16861    * HTML radio button.
16862    *
16863    * @param {string} ngModel Assignable angular expression to data-bind to.
16864    * @param {string} value The value to which the expression should be set when selected.
16865    * @param {string=} name Property name of the form under which the control is published.
16866    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16867    *    interaction with the input element.
16868    * @param {string} ngValue Angular expression which sets the value to which the expression should
16869    *    be set when selected.
16870    *
16871    * @example
16872       <example name="radio-input-directive" module="radioExample">
16873         <file name="index.html">
16874          <script>
16875            angular.module('radioExample', [])
16876              .controller('ExampleController', ['$scope', function($scope) {
16877                $scope.color = 'blue';
16878                $scope.specialValue = {
16879                  "id": "12345",
16880                  "value": "green"
16881                };
16882              }]);
16883          </script>
16884          <form name="myForm" ng-controller="ExampleController">
16885            <input type="radio" ng-model="color" value="red">  Red <br/>
16886            <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16887            <input type="radio" ng-model="color" value="blue"> Blue <br/>
16888            <tt>color = {{color | json}}</tt><br/>
16889           </form>
16890           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16891         </file>
16892         <file name="protractor.js" type="protractor">
16893           it('should change state', function() {
16894             var color = element(by.binding('color'));
16895
16896             expect(color.getText()).toContain('blue');
16897
16898             element.all(by.model('color')).get(0).click();
16899
16900             expect(color.getText()).toContain('red');
16901           });
16902         </file>
16903       </example>
16904    */
16905   'radio': radioInputType,
16906
16907
16908   /**
16909    * @ngdoc input
16910    * @name input[checkbox]
16911    *
16912    * @description
16913    * HTML checkbox.
16914    *
16915    * @param {string} ngModel Assignable angular expression to data-bind to.
16916    * @param {string=} name Property name of the form under which the control is published.
16917    * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16918    * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16919    * @param {string=} ngChange Angular expression to be executed when input changes due to user
16920    *    interaction with the input element.
16921    *
16922    * @example
16923       <example name="checkbox-input-directive" module="checkboxExample">
16924         <file name="index.html">
16925          <script>
16926            angular.module('checkboxExample', [])
16927              .controller('ExampleController', ['$scope', function($scope) {
16928                $scope.value1 = true;
16929                $scope.value2 = 'YES'
16930              }]);
16931          </script>
16932          <form name="myForm" ng-controller="ExampleController">
16933            Value1: <input type="checkbox" ng-model="value1"> <br/>
16934            Value2: <input type="checkbox" ng-model="value2"
16935                           ng-true-value="YES" ng-false-value="NO"> <br/>
16936            <tt>value1 = {{value1}}</tt><br/>
16937            <tt>value2 = {{value2}}</tt><br/>
16938           </form>
16939         </file>
16940         <file name="protractor.js" type="protractor">
16941           it('should change state', function() {
16942             var value1 = element(by.binding('value1'));
16943             var value2 = element(by.binding('value2'));
16944
16945             expect(value1.getText()).toContain('true');
16946             expect(value2.getText()).toContain('YES');
16947
16948             element(by.model('value1')).click();
16949             element(by.model('value2')).click();
16950
16951             expect(value1.getText()).toContain('false');
16952             expect(value2.getText()).toContain('NO');
16953           });
16954         </file>
16955       </example>
16956    */
16957   'checkbox': checkboxInputType,
16958
16959   'hidden': noop,
16960   'button': noop,
16961   'submit': noop,
16962   'reset': noop,
16963   'file': noop
16964 };
16965
16966 // A helper function to call $setValidity and return the value / undefined,
16967 // a pattern that is repeated a lot in the input validation logic.
16968 function validate(ctrl, validatorName, validity, value){
16969   ctrl.$setValidity(validatorName, validity);
16970   return validity ? value : undefined;
16971 }
16972
16973 function testFlags(validity, flags) {
16974   var i, flag;
16975   if (flags) {
16976     for (i=0; i<flags.length; ++i) {
16977       flag = flags[i];
16978       if (validity[flag]) {
16979         return true;
16980       }
16981     }
16982   }
16983   return false;
16984 }
16985
16986 // Pass validity so that behaviour can be mocked easier.
16987 function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
16988   if (isObject(validity)) {
16989     ctrl.$$hasNativeValidators = true;
16990     var validator = function(value) {
16991       // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
16992       // perform the required validation)
16993       if (!ctrl.$error[validatorName] &&
16994           !testFlags(validity, ignoreFlags) &&
16995           testFlags(validity, badFlags)) {
16996         ctrl.$setValidity(validatorName, false);
16997         return;
16998       }
16999       return value;
17000     };
17001     ctrl.$parsers.push(validator);
17002   }
17003 }
17004
17005 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17006   var validity = element.prop(VALIDITY_STATE_PROPERTY);
17007   var placeholder = element[0].placeholder, noevent = {};
17008   var type = lowercase(element[0].type);
17009   ctrl.$$validityState = validity;
17010
17011   // In composition mode, users are still inputing intermediate text buffer,
17012   // hold the listener until composition is done.
17013   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
17014   if (!$sniffer.android) {
17015     var composing = false;
17016
17017     element.on('compositionstart', function(data) {
17018       composing = true;
17019     });
17020
17021     element.on('compositionend', function() {
17022       composing = false;
17023       listener();
17024     });
17025   }
17026
17027   var listener = function(ev) {
17028     if (composing) return;
17029     var value = element.val();
17030
17031     // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
17032     // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
17033     // IE also sends input events for other non-input-related things, (such as focusing on a
17034     // form control), so this change is not entirely enough to solve this.
17035     if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
17036       placeholder = element[0].placeholder;
17037       return;
17038     }
17039
17040     // By default we will trim the value
17041     // If the attribute ng-trim exists we will avoid trimming
17042     // If input type is 'password', the value is never trimmed
17043     if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
17044       value = trim(value);
17045     }
17046
17047     // If a control is suffering from bad input, browsers discard its value, so it may be
17048     // necessary to revalidate even if the control's value is the same empty value twice in
17049     // a row.
17050     var revalidate = validity && ctrl.$$hasNativeValidators;
17051     if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
17052       if (scope.$root.$$phase) {
17053         ctrl.$setViewValue(value);
17054       } else {
17055         scope.$apply(function() {
17056           ctrl.$setViewValue(value);
17057         });
17058       }
17059     }
17060   };
17061
17062   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
17063   // input event on backspace, delete or cut
17064   if ($sniffer.hasEvent('input')) {
17065     element.on('input', listener);
17066   } else {
17067     var timeout;
17068
17069     var deferListener = function() {
17070       if (!timeout) {
17071         timeout = $browser.defer(function() {
17072           listener();
17073           timeout = null;
17074         });
17075       }
17076     };
17077
17078     element.on('keydown', function(event) {
17079       var key = event.keyCode;
17080
17081       // ignore
17082       //    command            modifiers                   arrows
17083       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
17084
17085       deferListener();
17086     });
17087
17088     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
17089     if ($sniffer.hasEvent('paste')) {
17090       element.on('paste cut', deferListener);
17091     }
17092   }
17093
17094   // if user paste into input using mouse on older browser
17095   // or form autocomplete on newer browser, we need "change" event to catch it
17096   element.on('change', listener);
17097
17098   ctrl.$render = function() {
17099     element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
17100   };
17101
17102   // pattern validator
17103   var pattern = attr.ngPattern,
17104       patternValidator,
17105       match;
17106
17107   if (pattern) {
17108     var validateRegex = function(regexp, value) {
17109       return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
17110     };
17111     match = pattern.match(/^\/(.*)\/([gim]*)$/);
17112     if (match) {
17113       pattern = new RegExp(match[1], match[2]);
17114       patternValidator = function(value) {
17115         return validateRegex(pattern, value);
17116       };
17117     } else {
17118       patternValidator = function(value) {
17119         var patternObj = scope.$eval(pattern);
17120
17121         if (!patternObj || !patternObj.test) {
17122           throw minErr('ngPattern')('noregexp',
17123             'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
17124             patternObj, startingTag(element));
17125         }
17126         return validateRegex(patternObj, value);
17127       };
17128     }
17129
17130     ctrl.$formatters.push(patternValidator);
17131     ctrl.$parsers.push(patternValidator);
17132   }
17133
17134   // min length validator
17135   if (attr.ngMinlength) {
17136     var minlength = int(attr.ngMinlength);
17137     var minLengthValidator = function(value) {
17138       return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
17139     };
17140
17141     ctrl.$parsers.push(minLengthValidator);
17142     ctrl.$formatters.push(minLengthValidator);
17143   }
17144
17145   // max length validator
17146   if (attr.ngMaxlength) {
17147     var maxlength = int(attr.ngMaxlength);
17148     var maxLengthValidator = function(value) {
17149       return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
17150     };
17151
17152     ctrl.$parsers.push(maxLengthValidator);
17153     ctrl.$formatters.push(maxLengthValidator);
17154   }
17155 }
17156
17157 var numberBadFlags = ['badInput'];
17158
17159 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17160   textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17161
17162   ctrl.$parsers.push(function(value) {
17163     var empty = ctrl.$isEmpty(value);
17164     if (empty || NUMBER_REGEXP.test(value)) {
17165       ctrl.$setValidity('number', true);
17166       return value === '' ? null : (empty ? value : parseFloat(value));
17167     } else {
17168       ctrl.$setValidity('number', false);
17169       return undefined;
17170     }
17171   });
17172
17173   addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
17174
17175   ctrl.$formatters.push(function(value) {
17176     return ctrl.$isEmpty(value) ? '' : '' + value;
17177   });
17178
17179   if (attr.min) {
17180     var minValidator = function(value) {
17181       var min = parseFloat(attr.min);
17182       return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
17183     };
17184
17185     ctrl.$parsers.push(minValidator);
17186     ctrl.$formatters.push(minValidator);
17187   }
17188
17189   if (attr.max) {
17190     var maxValidator = function(value) {
17191       var max = parseFloat(attr.max);
17192       return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
17193     };
17194
17195     ctrl.$parsers.push(maxValidator);
17196     ctrl.$formatters.push(maxValidator);
17197   }
17198
17199   ctrl.$formatters.push(function(value) {
17200     return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
17201   });
17202 }
17203
17204 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17205   textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17206
17207   var urlValidator = function(value) {
17208     return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
17209   };
17210
17211   ctrl.$formatters.push(urlValidator);
17212   ctrl.$parsers.push(urlValidator);
17213 }
17214
17215 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17216   textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17217
17218   var emailValidator = function(value) {
17219     return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
17220   };
17221
17222   ctrl.$formatters.push(emailValidator);
17223   ctrl.$parsers.push(emailValidator);
17224 }
17225
17226 function radioInputType(scope, element, attr, ctrl) {
17227   // make the name unique, if not defined
17228   if (isUndefined(attr.name)) {
17229     element.attr('name', nextUid());
17230   }
17231
17232   element.on('click', function() {
17233     if (element[0].checked) {
17234       scope.$apply(function() {
17235         ctrl.$setViewValue(attr.value);
17236       });
17237     }
17238   });
17239
17240   ctrl.$render = function() {
17241     var value = attr.value;
17242     element[0].checked = (value == ctrl.$viewValue);
17243   };
17244
17245   attr.$observe('value', ctrl.$render);
17246 }
17247
17248 function checkboxInputType(scope, element, attr, ctrl) {
17249   var trueValue = attr.ngTrueValue,
17250       falseValue = attr.ngFalseValue;
17251
17252   if (!isString(trueValue)) trueValue = true;
17253   if (!isString(falseValue)) falseValue = false;
17254
17255   element.on('click', function() {
17256     scope.$apply(function() {
17257       ctrl.$setViewValue(element[0].checked);
17258     });
17259   });
17260
17261   ctrl.$render = function() {
17262     element[0].checked = ctrl.$viewValue;
17263   };
17264
17265   // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
17266   ctrl.$isEmpty = function(value) {
17267     return value !== trueValue;
17268   };
17269
17270   ctrl.$formatters.push(function(value) {
17271     return value === trueValue;
17272   });
17273
17274   ctrl.$parsers.push(function(value) {
17275     return value ? trueValue : falseValue;
17276   });
17277 }
17278
17279
17280 /**
17281  * @ngdoc directive
17282  * @name textarea
17283  * @restrict E
17284  *
17285  * @description
17286  * HTML textarea element control with angular data-binding. The data-binding and validation
17287  * properties of this element are exactly the same as those of the
17288  * {@link ng.directive:input input element}.
17289  *
17290  * @param {string} ngModel Assignable angular expression to data-bind to.
17291  * @param {string=} name Property name of the form under which the control is published.
17292  * @param {string=} required Sets `required` validation error key if the value is not entered.
17293  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17294  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17295  *    `required` when you want to data-bind to the `required` attribute.
17296  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17297  *    minlength.
17298  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17299  *    maxlength.
17300  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17301  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17302  *    patterns defined as scope expressions.
17303  * @param {string=} ngChange Angular expression to be executed when input changes due to user
17304  *    interaction with the input element.
17305  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17306  */
17307
17308
17309 /**
17310  * @ngdoc directive
17311  * @name input
17312  * @restrict E
17313  *
17314  * @description
17315  * HTML input element control with angular data-binding. Input control follows HTML5 input types
17316  * and polyfills the HTML5 validation behavior for older browsers.
17317  *
17318  * *NOTE* Not every feature offered is available for all input types.
17319  *
17320  * @param {string} ngModel Assignable angular expression to data-bind to.
17321  * @param {string=} name Property name of the form under which the control is published.
17322  * @param {string=} required Sets `required` validation error key if the value is not entered.
17323  * @param {boolean=} ngRequired Sets `required` attribute if set to true
17324  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17325  *    minlength.
17326  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17327  *    maxlength.
17328  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17329  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17330  *    patterns defined as scope expressions.
17331  * @param {string=} ngChange Angular expression to be executed when input changes due to user
17332  *    interaction with the input element.
17333  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17334  *    This parameter is ignored for input[type=password] controls, which will never trim the
17335  *    input.
17336  *
17337  * @example
17338     <example name="input-directive" module="inputExample">
17339       <file name="index.html">
17340        <script>
17341           angular.module('inputExample', [])
17342             .controller('ExampleController', ['$scope', function($scope) {
17343               $scope.user = {name: 'guest', last: 'visitor'};
17344             }]);
17345        </script>
17346        <div ng-controller="ExampleController">
17347          <form name="myForm">
17348            User name: <input type="text" name="userName" ng-model="user.name" required>
17349            <span class="error" ng-show="myForm.userName.$error.required">
17350              Required!</span><br>
17351            Last name: <input type="text" name="lastName" ng-model="user.last"
17352              ng-minlength="3" ng-maxlength="10">
17353            <span class="error" ng-show="myForm.lastName.$error.minlength">
17354              Too short!</span>
17355            <span class="error" ng-show="myForm.lastName.$error.maxlength">
17356              Too long!</span><br>
17357          </form>
17358          <hr>
17359          <tt>user = {{user}}</tt><br/>
17360          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
17361          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
17362          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
17363          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
17364          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
17365          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
17366          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
17367          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
17368        </div>
17369       </file>
17370       <file name="protractor.js" type="protractor">
17371         var user = element(by.binding('{{user}}'));
17372         var userNameValid = element(by.binding('myForm.userName.$valid'));
17373         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
17374         var lastNameError = element(by.binding('myForm.lastName.$error'));
17375         var formValid = element(by.binding('myForm.$valid'));
17376         var userNameInput = element(by.model('user.name'));
17377         var userLastInput = element(by.model('user.last'));
17378
17379         it('should initialize to model', function() {
17380           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
17381           expect(userNameValid.getText()).toContain('true');
17382           expect(formValid.getText()).toContain('true');
17383         });
17384
17385         it('should be invalid if empty when required', function() {
17386           userNameInput.clear();
17387           userNameInput.sendKeys('');
17388
17389           expect(user.getText()).toContain('{"last":"visitor"}');
17390           expect(userNameValid.getText()).toContain('false');
17391           expect(formValid.getText()).toContain('false');
17392         });
17393
17394         it('should be valid if empty when min length is set', function() {
17395           userLastInput.clear();
17396           userLastInput.sendKeys('');
17397
17398           expect(user.getText()).toContain('{"name":"guest","last":""}');
17399           expect(lastNameValid.getText()).toContain('true');
17400           expect(formValid.getText()).toContain('true');
17401         });
17402
17403         it('should be invalid if less than required min length', function() {
17404           userLastInput.clear();
17405           userLastInput.sendKeys('xx');
17406
17407           expect(user.getText()).toContain('{"name":"guest"}');
17408           expect(lastNameValid.getText()).toContain('false');
17409           expect(lastNameError.getText()).toContain('minlength');
17410           expect(formValid.getText()).toContain('false');
17411         });
17412
17413         it('should be invalid if longer than max length', function() {
17414           userLastInput.clear();
17415           userLastInput.sendKeys('some ridiculously long name');
17416
17417           expect(user.getText()).toContain('{"name":"guest"}');
17418           expect(lastNameValid.getText()).toContain('false');
17419           expect(lastNameError.getText()).toContain('maxlength');
17420           expect(formValid.getText()).toContain('false');
17421         });
17422       </file>
17423     </example>
17424  */
17425 var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
17426   return {
17427     restrict: 'E',
17428     require: '?ngModel',
17429     link: function(scope, element, attr, ctrl) {
17430       if (ctrl) {
17431         (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17432                                                             $browser);
17433       }
17434     }
17435   };
17436 }];
17437
17438 var VALID_CLASS = 'ng-valid',
17439     INVALID_CLASS = 'ng-invalid',
17440     PRISTINE_CLASS = 'ng-pristine',
17441     DIRTY_CLASS = 'ng-dirty';
17442
17443 /**
17444  * @ngdoc type
17445  * @name ngModel.NgModelController
17446  *
17447  * @property {string} $viewValue Actual string value in the view.
17448  * @property {*} $modelValue The value in the model, that the control is bound to.
17449  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17450        the control reads value from the DOM.  Each function is called, in turn, passing the value
17451        through to the next. The last return value is used to populate the model.
17452        Used to sanitize / convert the value as well as validation. For validation,
17453        the parsers should update the validity state using
17454        {@link ngModel.NgModelController#$setValidity $setValidity()},
17455        and return `undefined` for invalid values.
17456
17457  *
17458  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17459        the model value changes. Each function is called, in turn, passing the value through to the
17460        next. Used to format / convert values for display in the control and validation.
17461  * ```js
17462  * function formatter(value) {
17463  *   if (value) {
17464  *     return value.toUpperCase();
17465  *   }
17466  * }
17467  * ngModel.$formatters.push(formatter);
17468  * ```
17469  *
17470  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17471  *     view value has changed. It is called with no arguments, and its return value is ignored.
17472  *     This can be used in place of additional $watches against the model value.
17473  *
17474  * @property {Object} $error An object hash with all errors as keys.
17475  *
17476  * @property {boolean} $pristine True if user has not interacted with the control yet.
17477  * @property {boolean} $dirty True if user has already interacted with the control.
17478  * @property {boolean} $valid True if there is no error.
17479  * @property {boolean} $invalid True if at least one error on the control.
17480  *
17481  * @description
17482  *
17483  * `NgModelController` provides API for the `ng-model` directive. The controller contains
17484  * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17485  * purposefully does not contain any logic which deals with DOM rendering or listening to
17486  * DOM events. Such DOM related logic should be provided by other directives which make use of
17487  * `NgModelController` for data-binding.
17488  *
17489  * ## Custom Control Example
17490  * This example shows how to use `NgModelController` with a custom control to achieve
17491  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17492  * collaborate together to achieve the desired result.
17493  *
17494  * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17495  * contents be edited in place by the user.  This will not work on older browsers.
17496  *
17497  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
17498  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
17499  * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
17500  * that content using the `$sce` service.
17501  *
17502  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
17503     <file name="style.css">
17504       [contenteditable] {
17505         border: 1px solid black;
17506         background-color: white;
17507         min-height: 20px;
17508       }
17509
17510       .ng-invalid {
17511         border: 1px solid red;
17512       }
17513
17514     </file>
17515     <file name="script.js">
17516       angular.module('customControl', ['ngSanitize']).
17517         directive('contenteditable', ['$sce', function($sce) {
17518           return {
17519             restrict: 'A', // only activate on element attribute
17520             require: '?ngModel', // get a hold of NgModelController
17521             link: function(scope, element, attrs, ngModel) {
17522               if(!ngModel) return; // do nothing if no ng-model
17523
17524               // Specify how UI should be updated
17525               ngModel.$render = function() {
17526                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
17527               };
17528
17529               // Listen for change events to enable binding
17530               element.on('blur keyup change', function() {
17531                 scope.$apply(read);
17532               });
17533               read(); // initialize
17534
17535               // Write data to the model
17536               function read() {
17537                 var html = element.html();
17538                 // When we clear the content editable the browser leaves a <br> behind
17539                 // If strip-br attribute is provided then we strip this out
17540                 if( attrs.stripBr && html == '<br>' ) {
17541                   html = '';
17542                 }
17543                 ngModel.$setViewValue(html);
17544               }
17545             }
17546           };
17547         }]);
17548     </file>
17549     <file name="index.html">
17550       <form name="myForm">
17551        <div contenteditable
17552             name="myWidget" ng-model="userContent"
17553             strip-br="true"
17554             required>Change me!</div>
17555         <span ng-show="myForm.myWidget.$error.required">Required!</span>
17556        <hr>
17557        <textarea ng-model="userContent"></textarea>
17558       </form>
17559     </file>
17560     <file name="protractor.js" type="protractor">
17561     it('should data-bind and become invalid', function() {
17562       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17563         // SafariDriver can't handle contenteditable
17564         // and Firefox driver can't clear contenteditables very well
17565         return;
17566       }
17567       var contentEditable = element(by.css('[contenteditable]'));
17568       var content = 'Change me!';
17569
17570       expect(contentEditable.getText()).toEqual(content);
17571
17572       contentEditable.clear();
17573       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17574       expect(contentEditable.getText()).toEqual('');
17575       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17576     });
17577     </file>
17578  * </example>
17579  *
17580  *
17581  */
17582 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17583     function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17584   this.$viewValue = Number.NaN;
17585   this.$modelValue = Number.NaN;
17586   this.$parsers = [];
17587   this.$formatters = [];
17588   this.$viewChangeListeners = [];
17589   this.$pristine = true;
17590   this.$dirty = false;
17591   this.$valid = true;
17592   this.$invalid = false;
17593   this.$name = $attr.name;
17594
17595   var ngModelGet = $parse($attr.ngModel),
17596       ngModelSet = ngModelGet.assign;
17597
17598   if (!ngModelSet) {
17599     throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17600         $attr.ngModel, startingTag($element));
17601   }
17602
17603   /**
17604    * @ngdoc method
17605    * @name ngModel.NgModelController#$render
17606    *
17607    * @description
17608    * Called when the view needs to be updated. It is expected that the user of the ng-model
17609    * directive will implement this method.
17610    */
17611   this.$render = noop;
17612
17613   /**
17614    * @ngdoc method
17615    * @name ngModel.NgModelController#$isEmpty
17616    *
17617    * @description
17618    * This is called when we need to determine if the value of the input is empty.
17619    *
17620    * For instance, the required directive does this to work out if the input has data or not.
17621    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17622    *
17623    * You can override this for input directives whose concept of being empty is different to the
17624    * default. The `checkboxInputType` directive does this because in its case a value of `false`
17625    * implies empty.
17626    *
17627    * @param {*} value Reference to check.
17628    * @returns {boolean} True if `value` is empty.
17629    */
17630   this.$isEmpty = function(value) {
17631     return isUndefined(value) || value === '' || value === null || value !== value;
17632   };
17633
17634   var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17635       invalidCount = 0, // used to easily determine if we are valid
17636       $error = this.$error = {}; // keep invalid keys here
17637
17638
17639   // Setup initial state of the control
17640   $element.addClass(PRISTINE_CLASS);
17641   toggleValidCss(true);
17642
17643   // convenience method for easy toggling of classes
17644   function toggleValidCss(isValid, validationErrorKey) {
17645     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17646     $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17647     $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17648   }
17649
17650   /**
17651    * @ngdoc method
17652    * @name ngModel.NgModelController#$setValidity
17653    *
17654    * @description
17655    * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17656    * does not notify form if given validator is already marked as invalid).
17657    *
17658    * This method should be called by validators - i.e. the parser or formatter functions.
17659    *
17660    * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17661    *        to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
17662    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17663    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17664    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17665    * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17666    */
17667   this.$setValidity = function(validationErrorKey, isValid) {
17668     // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17669     // jshint -W018
17670     if ($error[validationErrorKey] === !isValid) return;
17671     // jshint +W018
17672
17673     if (isValid) {
17674       if ($error[validationErrorKey]) invalidCount--;
17675       if (!invalidCount) {
17676         toggleValidCss(true);
17677         this.$valid = true;
17678         this.$invalid = false;
17679       }
17680     } else {
17681       toggleValidCss(false);
17682       this.$invalid = true;
17683       this.$valid = false;
17684       invalidCount++;
17685     }
17686
17687     $error[validationErrorKey] = !isValid;
17688     toggleValidCss(isValid, validationErrorKey);
17689
17690     parentForm.$setValidity(validationErrorKey, isValid, this);
17691   };
17692
17693   /**
17694    * @ngdoc method
17695    * @name ngModel.NgModelController#$setPristine
17696    *
17697    * @description
17698    * Sets the control to its pristine state.
17699    *
17700    * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17701    * state (ng-pristine class).
17702    */
17703   this.$setPristine = function () {
17704     this.$dirty = false;
17705     this.$pristine = true;
17706     $animate.removeClass($element, DIRTY_CLASS);
17707     $animate.addClass($element, PRISTINE_CLASS);
17708   };
17709
17710   /**
17711    * @ngdoc method
17712    * @name ngModel.NgModelController#$setViewValue
17713    *
17714    * @description
17715    * Update the view value.
17716    *
17717    * This method should be called when the view value changes, typically from within a DOM event handler.
17718    * For example {@link ng.directive:input input} and
17719    * {@link ng.directive:select select} directives call it.
17720    *
17721    * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17722    * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17723    * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17724    *
17725    * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17726    *
17727    * Note that calling this function does not trigger a `$digest`.
17728    *
17729    * @param {string} value Value from the view.
17730    */
17731   this.$setViewValue = function(value) {
17732     this.$viewValue = value;
17733
17734     // change to dirty
17735     if (this.$pristine) {
17736       this.$dirty = true;
17737       this.$pristine = false;
17738       $animate.removeClass($element, PRISTINE_CLASS);
17739       $animate.addClass($element, DIRTY_CLASS);
17740       parentForm.$setDirty();
17741     }
17742
17743     forEach(this.$parsers, function(fn) {
17744       value = fn(value);
17745     });
17746
17747     if (this.$modelValue !== value) {
17748       this.$modelValue = value;
17749       ngModelSet($scope, value);
17750       forEach(this.$viewChangeListeners, function(listener) {
17751         try {
17752           listener();
17753         } catch(e) {
17754           $exceptionHandler(e);
17755         }
17756       });
17757     }
17758   };
17759
17760   // model -> value
17761   var ctrl = this;
17762
17763   $scope.$watch(function ngModelWatch() {
17764     var value = ngModelGet($scope);
17765
17766     // if scope model value and ngModel value are out of sync
17767     if (ctrl.$modelValue !== value) {
17768
17769       var formatters = ctrl.$formatters,
17770           idx = formatters.length;
17771
17772       ctrl.$modelValue = value;
17773       while(idx--) {
17774         value = formatters[idx](value);
17775       }
17776
17777       if (ctrl.$viewValue !== value) {
17778         ctrl.$viewValue = value;
17779         ctrl.$render();
17780       }
17781     }
17782
17783     return value;
17784   });
17785 }];
17786
17787
17788 /**
17789  * @ngdoc directive
17790  * @name ngModel
17791  *
17792  * @element input
17793  *
17794  * @description
17795  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17796  * property on the scope using {@link ngModel.NgModelController NgModelController},
17797  * which is created and exposed by this directive.
17798  *
17799  * `ngModel` is responsible for:
17800  *
17801  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17802  *   require.
17803  * - Providing validation behavior (i.e. required, number, email, url).
17804  * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17805  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17806  * - Registering the control with its parent {@link ng.directive:form form}.
17807  *
17808  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17809  * current scope. If the property doesn't already exist on this scope, it will be created
17810  * implicitly and added to the scope.
17811  *
17812  * For best practices on using `ngModel`, see:
17813  *
17814  *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
17815  *
17816  * For basic examples, how to use `ngModel`, see:
17817  *
17818  *  - {@link ng.directive:input input}
17819  *    - {@link input[text] text}
17820  *    - {@link input[checkbox] checkbox}
17821  *    - {@link input[radio] radio}
17822  *    - {@link input[number] number}
17823  *    - {@link input[email] email}
17824  *    - {@link input[url] url}
17825  *  - {@link ng.directive:select select}
17826  *  - {@link ng.directive:textarea textarea}
17827  *
17828  * # CSS classes
17829  * The following CSS classes are added and removed on the associated input/select/textarea element
17830  * depending on the validity of the model.
17831  *
17832  *  - `ng-valid` is set if the model is valid.
17833  *  - `ng-invalid` is set if the model is invalid.
17834  *  - `ng-pristine` is set if the model is pristine.
17835  *  - `ng-dirty` is set if the model is dirty.
17836  *
17837  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
17838  *
17839  * ## Animation Hooks
17840  *
17841  * Animations within models are triggered when any of the associated CSS classes are added and removed
17842  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
17843  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
17844  * The animations that are triggered within ngModel are similar to how they work in ngClass and
17845  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
17846  *
17847  * The following example shows a simple way to utilize CSS transitions to style an input element
17848  * that has been rendered as invalid after it has been validated:
17849  *
17850  * <pre>
17851  * //be sure to include ngAnimate as a module to hook into more
17852  * //advanced animations
17853  * .my-input {
17854  *   transition:0.5s linear all;
17855  *   background: white;
17856  * }
17857  * .my-input.ng-invalid {
17858  *   background: red;
17859  *   color:white;
17860  * }
17861  * </pre>
17862  *
17863  * @example
17864  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
17865      <file name="index.html">
17866        <script>
17867         angular.module('inputExample', [])
17868           .controller('ExampleController', ['$scope', function($scope) {
17869             $scope.val = '1';
17870           }]);
17871        </script>
17872        <style>
17873          .my-input {
17874            -webkit-transition:all linear 0.5s;
17875            transition:all linear 0.5s;
17876            background: transparent;
17877          }
17878          .my-input.ng-invalid {
17879            color:white;
17880            background: red;
17881          }
17882        </style>
17883        Update input to see transitions when valid/invalid.
17884        Integer is a valid value.
17885        <form name="testForm" ng-controller="ExampleController">
17886          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
17887        </form>
17888      </file>
17889  * </example>
17890  */
17891 var ngModelDirective = function() {
17892   return {
17893     require: ['ngModel', '^?form'],
17894     controller: NgModelController,
17895     link: function(scope, element, attr, ctrls) {
17896       // notify others, especially parent forms
17897
17898       var modelCtrl = ctrls[0],
17899           formCtrl = ctrls[1] || nullFormCtrl;
17900
17901       formCtrl.$addControl(modelCtrl);
17902
17903       scope.$on('$destroy', function() {
17904         formCtrl.$removeControl(modelCtrl);
17905       });
17906     }
17907   };
17908 };
17909
17910
17911 /**
17912  * @ngdoc directive
17913  * @name ngChange
17914  *
17915  * @description
17916  * Evaluate the given expression when the user changes the input.
17917  * The expression is evaluated immediately, unlike the JavaScript onchange event
17918  * which only triggers at the end of a change (usually, when the user leaves the
17919  * form element or presses the return key).
17920  * The expression is not evaluated when the value change is coming from the model.
17921  *
17922  * Note, this directive requires `ngModel` to be present.
17923  *
17924  * @element input
17925  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17926  * in input value.
17927  *
17928  * @example
17929  * <example name="ngChange-directive" module="changeExample">
17930  *   <file name="index.html">
17931  *     <script>
17932  *       angular.module('changeExample', [])
17933  *         .controller('ExampleController', ['$scope', function($scope) {
17934  *           $scope.counter = 0;
17935  *           $scope.change = function() {
17936  *             $scope.counter++;
17937  *           };
17938  *         }]);
17939  *     </script>
17940  *     <div ng-controller="ExampleController">
17941  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17942  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17943  *       <label for="ng-change-example2">Confirmed</label><br />
17944  *       <tt>debug = {{confirmed}}</tt><br/>
17945  *       <tt>counter = {{counter}}</tt><br/>
17946  *     </div>
17947  *   </file>
17948  *   <file name="protractor.js" type="protractor">
17949  *     var counter = element(by.binding('counter'));
17950  *     var debug = element(by.binding('confirmed'));
17951  *
17952  *     it('should evaluate the expression if changing from view', function() {
17953  *       expect(counter.getText()).toContain('0');
17954  *
17955  *       element(by.id('ng-change-example1')).click();
17956  *
17957  *       expect(counter.getText()).toContain('1');
17958  *       expect(debug.getText()).toContain('true');
17959  *     });
17960  *
17961  *     it('should not evaluate the expression if changing from model', function() {
17962  *       element(by.id('ng-change-example2')).click();
17963
17964  *       expect(counter.getText()).toContain('0');
17965  *       expect(debug.getText()).toContain('true');
17966  *     });
17967  *   </file>
17968  * </example>
17969  */
17970 var ngChangeDirective = valueFn({
17971   require: 'ngModel',
17972   link: function(scope, element, attr, ctrl) {
17973     ctrl.$viewChangeListeners.push(function() {
17974       scope.$eval(attr.ngChange);
17975     });
17976   }
17977 });
17978
17979
17980 var requiredDirective = function() {
17981   return {
17982     require: '?ngModel',
17983     link: function(scope, elm, attr, ctrl) {
17984       if (!ctrl) return;
17985       attr.required = true; // force truthy in case we are on non input element
17986
17987       var validator = function(value) {
17988         if (attr.required && ctrl.$isEmpty(value)) {
17989           ctrl.$setValidity('required', false);
17990           return;
17991         } else {
17992           ctrl.$setValidity('required', true);
17993           return value;
17994         }
17995       };
17996
17997       ctrl.$formatters.push(validator);
17998       ctrl.$parsers.unshift(validator);
17999
18000       attr.$observe('required', function() {
18001         validator(ctrl.$viewValue);
18002       });
18003     }
18004   };
18005 };
18006
18007
18008 /**
18009  * @ngdoc directive
18010  * @name ngList
18011  *
18012  * @description
18013  * Text input that converts between a delimited string and an array of strings. The delimiter
18014  * can be a fixed string (by default a comma) or a regular expression.
18015  *
18016  * @element input
18017  * @param {string=} ngList optional delimiter that should be used to split the value. If
18018  *   specified in form `/something/` then the value will be converted into a regular expression.
18019  *
18020  * @example
18021     <example name="ngList-directive" module="listExample">
18022       <file name="index.html">
18023        <script>
18024          angular.module('listExample', [])
18025            .controller('ExampleController', ['$scope', function($scope) {
18026              $scope.names = ['igor', 'misko', 'vojta'];
18027            }]);
18028        </script>
18029        <form name="myForm" ng-controller="ExampleController">
18030          List: <input name="namesInput" ng-model="names" ng-list required>
18031          <span class="error" ng-show="myForm.namesInput.$error.required">
18032            Required!</span>
18033          <br>
18034          <tt>names = {{names}}</tt><br/>
18035          <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
18036          <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
18037          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18038          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18039         </form>
18040       </file>
18041       <file name="protractor.js" type="protractor">
18042         var listInput = element(by.model('names'));
18043         var names = element(by.binding('{{names}}'));
18044         var valid = element(by.binding('myForm.namesInput.$valid'));
18045         var error = element(by.css('span.error'));
18046
18047         it('should initialize to model', function() {
18048           expect(names.getText()).toContain('["igor","misko","vojta"]');
18049           expect(valid.getText()).toContain('true');
18050           expect(error.getCssValue('display')).toBe('none');
18051         });
18052
18053         it('should be invalid if empty', function() {
18054           listInput.clear();
18055           listInput.sendKeys('');
18056
18057           expect(names.getText()).toContain('');
18058           expect(valid.getText()).toContain('false');
18059           expect(error.getCssValue('display')).not.toBe('none');        });
18060       </file>
18061     </example>
18062  */
18063 var ngListDirective = function() {
18064   return {
18065     require: 'ngModel',
18066     link: function(scope, element, attr, ctrl) {
18067       var match = /\/(.*)\//.exec(attr.ngList),
18068           separator = match && new RegExp(match[1]) || attr.ngList || ',';
18069
18070       var parse = function(viewValue) {
18071         // If the viewValue is invalid (say required but empty) it will be `undefined`
18072         if (isUndefined(viewValue)) return;
18073
18074         var list = [];
18075
18076         if (viewValue) {
18077           forEach(viewValue.split(separator), function(value) {
18078             if (value) list.push(trim(value));
18079           });
18080         }
18081
18082         return list;
18083       };
18084
18085       ctrl.$parsers.push(parse);
18086       ctrl.$formatters.push(function(value) {
18087         if (isArray(value)) {
18088           return value.join(', ');
18089         }
18090
18091         return undefined;
18092       });
18093
18094       // Override the standard $isEmpty because an empty array means the input is empty.
18095       ctrl.$isEmpty = function(value) {
18096         return !value || !value.length;
18097       };
18098     }
18099   };
18100 };
18101
18102
18103 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
18104 /**
18105  * @ngdoc directive
18106  * @name ngValue
18107  *
18108  * @description
18109  * Binds the given expression to the value of `input[select]` or `input[radio]`, so
18110  * that when the element is selected, the `ngModel` of that element is set to the
18111  * bound value.
18112  *
18113  * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
18114  * shown below.
18115  *
18116  * @element input
18117  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
18118  *   of the `input` element
18119  *
18120  * @example
18121     <example name="ngValue-directive" module="valueExample">
18122       <file name="index.html">
18123        <script>
18124           angular.module('valueExample', [])
18125             .controller('ExampleController', ['$scope', function($scope) {
18126               $scope.names = ['pizza', 'unicorns', 'robots'];
18127               $scope.my = { favorite: 'unicorns' };
18128             }]);
18129        </script>
18130         <form ng-controller="ExampleController">
18131           <h2>Which is your favorite?</h2>
18132             <label ng-repeat="name in names" for="{{name}}">
18133               {{name}}
18134               <input type="radio"
18135                      ng-model="my.favorite"
18136                      ng-value="name"
18137                      id="{{name}}"
18138                      name="favorite">
18139             </label>
18140           <div>You chose {{my.favorite}}</div>
18141         </form>
18142       </file>
18143       <file name="protractor.js" type="protractor">
18144         var favorite = element(by.binding('my.favorite'));
18145
18146         it('should initialize to model', function() {
18147           expect(favorite.getText()).toContain('unicorns');
18148         });
18149         it('should bind the values to the inputs', function() {
18150           element.all(by.model('my.favorite')).get(0).click();
18151           expect(favorite.getText()).toContain('pizza');
18152         });
18153       </file>
18154     </example>
18155  */
18156 var ngValueDirective = function() {
18157   return {
18158     priority: 100,
18159     compile: function(tpl, tplAttr) {
18160       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
18161         return function ngValueConstantLink(scope, elm, attr) {
18162           attr.$set('value', scope.$eval(attr.ngValue));
18163         };
18164       } else {
18165         return function ngValueLink(scope, elm, attr) {
18166           scope.$watch(attr.ngValue, function valueWatchAction(value) {
18167             attr.$set('value', value);
18168           });
18169         };
18170       }
18171     }
18172   };
18173 };
18174
18175 /**
18176  * @ngdoc directive
18177  * @name ngBind
18178  * @restrict AC
18179  *
18180  * @description
18181  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
18182  * with the value of a given expression, and to update the text content when the value of that
18183  * expression changes.
18184  *
18185  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
18186  * `{{ expression }}` which is similar but less verbose.
18187  *
18188  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
18189  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
18190  * element attribute, it makes the bindings invisible to the user while the page is loading.
18191  *
18192  * An alternative solution to this problem would be using the
18193  * {@link ng.directive:ngCloak ngCloak} directive.
18194  *
18195  *
18196  * @element ANY
18197  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
18198  *
18199  * @example
18200  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
18201    <example module="bindExample">
18202      <file name="index.html">
18203        <script>
18204          angular.module('bindExample', [])
18205            .controller('ExampleController', ['$scope', function($scope) {
18206              $scope.name = 'Whirled';
18207            }]);
18208        </script>
18209        <div ng-controller="ExampleController">
18210          Enter name: <input type="text" ng-model="name"><br>
18211          Hello <span ng-bind="name"></span>!
18212        </div>
18213      </file>
18214      <file name="protractor.js" type="protractor">
18215        it('should check ng-bind', function() {
18216          var nameInput = element(by.model('name'));
18217
18218          expect(element(by.binding('name')).getText()).toBe('Whirled');
18219          nameInput.clear();
18220          nameInput.sendKeys('world');
18221          expect(element(by.binding('name')).getText()).toBe('world');
18222        });
18223      </file>
18224    </example>
18225  */
18226 var ngBindDirective = ngDirective({
18227   compile: function(templateElement) {
18228     templateElement.addClass('ng-binding');
18229     return function (scope, element, attr) {
18230       element.data('$binding', attr.ngBind);
18231       scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
18232         // We are purposefully using == here rather than === because we want to
18233         // catch when value is "null or undefined"
18234         // jshint -W041
18235         element.text(value == undefined ? '' : value);
18236       });
18237     };
18238   }
18239 });
18240
18241
18242 /**
18243  * @ngdoc directive
18244  * @name ngBindTemplate
18245  *
18246  * @description
18247  * The `ngBindTemplate` directive specifies that the element
18248  * text content should be replaced with the interpolation of the template
18249  * in the `ngBindTemplate` attribute.
18250  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
18251  * expressions. This directive is needed since some HTML elements
18252  * (such as TITLE and OPTION) cannot contain SPAN elements.
18253  *
18254  * @element ANY
18255  * @param {string} ngBindTemplate template of form
18256  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
18257  *
18258  * @example
18259  * Try it here: enter text in text box and watch the greeting change.
18260    <example module="bindExample">
18261      <file name="index.html">
18262        <script>
18263          angular.module('bindExample', [])
18264            .controller('ExampleController', ['$scope', function ($scope) {
18265              $scope.salutation = 'Hello';
18266              $scope.name = 'World';
18267            }]);
18268        </script>
18269        <div ng-controller="ExampleController">
18270         Salutation: <input type="text" ng-model="salutation"><br>
18271         Name: <input type="text" ng-model="name"><br>
18272         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
18273        </div>
18274      </file>
18275      <file name="protractor.js" type="protractor">
18276        it('should check ng-bind', function() {
18277          var salutationElem = element(by.binding('salutation'));
18278          var salutationInput = element(by.model('salutation'));
18279          var nameInput = element(by.model('name'));
18280
18281          expect(salutationElem.getText()).toBe('Hello World!');
18282
18283          salutationInput.clear();
18284          salutationInput.sendKeys('Greetings');
18285          nameInput.clear();
18286          nameInput.sendKeys('user');
18287
18288          expect(salutationElem.getText()).toBe('Greetings user!');
18289        });
18290      </file>
18291    </example>
18292  */
18293 var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
18294   return function(scope, element, attr) {
18295     // TODO: move this to scenario runner
18296     var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
18297     element.addClass('ng-binding').data('$binding', interpolateFn);
18298     attr.$observe('ngBindTemplate', function(value) {
18299       element.text(value);
18300     });
18301   };
18302 }];
18303
18304
18305 /**
18306  * @ngdoc directive
18307  * @name ngBindHtml
18308  *
18309  * @description
18310  * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
18311  * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
18312  * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
18313  * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
18314  * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
18315  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
18316  * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
18317  *
18318  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
18319  * will have an exception (instead of an exploit.)
18320  *
18321  * @element ANY
18322  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18323  *
18324  * @example
18325
18326    <example module="bindHtmlExample" deps="angular-sanitize.js">
18327      <file name="index.html">
18328        <div ng-controller="ExampleController">
18329         <p ng-bind-html="myHTML"></p>
18330        </div>
18331      </file>
18332
18333      <file name="script.js">
18334        angular.module('bindHtmlExample', ['ngSanitize'])
18335          .controller('ExampleController', ['$scope', function($scope) {
18336            $scope.myHTML =
18337               'I am an <code>HTML</code>string with ' +
18338               '<a href="#">links!</a> and other <em>stuff</em>';
18339          }]);
18340      </file>
18341
18342      <file name="protractor.js" type="protractor">
18343        it('should check ng-bind-html', function() {
18344          expect(element(by.binding('myHTML')).getText()).toBe(
18345              'I am an HTMLstring with links! and other stuff');
18346        });
18347      </file>
18348    </example>
18349  */
18350 var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
18351   return {
18352     compile: function (tElement) {
18353       tElement.addClass('ng-binding');
18354
18355       return function (scope, element, attr) {
18356         element.data('$binding', attr.ngBindHtml);
18357
18358         var parsed = $parse(attr.ngBindHtml);
18359
18360         function getStringValue() {
18361           return (parsed(scope) || '').toString();
18362         }
18363
18364         scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
18365           element.html($sce.getTrustedHtml(parsed(scope)) || '');
18366         });
18367       };
18368     }
18369   };
18370 }];
18371
18372 function classDirective(name, selector) {
18373   name = 'ngClass' + name;
18374   return ['$animate', function($animate) {
18375     return {
18376       restrict: 'AC',
18377       link: function(scope, element, attr) {
18378         var oldVal;
18379
18380         scope.$watch(attr[name], ngClassWatchAction, true);
18381
18382         attr.$observe('class', function(value) {
18383           ngClassWatchAction(scope.$eval(attr[name]));
18384         });
18385
18386
18387         if (name !== 'ngClass') {
18388           scope.$watch('$index', function($index, old$index) {
18389             // jshint bitwise: false
18390             var mod = $index & 1;
18391             if (mod !== (old$index & 1)) {
18392               var classes = arrayClasses(scope.$eval(attr[name]));
18393               mod === selector ?
18394                 addClasses(classes) :
18395                 removeClasses(classes);
18396             }
18397           });
18398         }
18399
18400         function addClasses(classes) {
18401           var newClasses = digestClassCounts(classes, 1);
18402           attr.$addClass(newClasses);
18403         }
18404
18405         function removeClasses(classes) {
18406           var newClasses = digestClassCounts(classes, -1);
18407           attr.$removeClass(newClasses);
18408         }
18409
18410         function digestClassCounts (classes, count) {
18411           var classCounts = element.data('$classCounts') || {};
18412           var classesToUpdate = [];
18413           forEach(classes, function (className) {
18414             if (count > 0 || classCounts[className]) {
18415               classCounts[className] = (classCounts[className] || 0) + count;
18416               if (classCounts[className] === +(count > 0)) {
18417                 classesToUpdate.push(className);
18418               }
18419             }
18420           });
18421           element.data('$classCounts', classCounts);
18422           return classesToUpdate.join(' ');
18423         }
18424
18425         function updateClasses (oldClasses, newClasses) {
18426           var toAdd = arrayDifference(newClasses, oldClasses);
18427           var toRemove = arrayDifference(oldClasses, newClasses);
18428           toRemove = digestClassCounts(toRemove, -1);
18429           toAdd = digestClassCounts(toAdd, 1);
18430
18431           if (toAdd.length === 0) {
18432             $animate.removeClass(element, toRemove);
18433           } else if (toRemove.length === 0) {
18434             $animate.addClass(element, toAdd);
18435           } else {
18436             $animate.setClass(element, toAdd, toRemove);
18437           }
18438         }
18439
18440         function ngClassWatchAction(newVal) {
18441           if (selector === true || scope.$index % 2 === selector) {
18442             var newClasses = arrayClasses(newVal || []);
18443             if (!oldVal) {
18444               addClasses(newClasses);
18445             } else if (!equals(newVal,oldVal)) {
18446               var oldClasses = arrayClasses(oldVal);
18447               updateClasses(oldClasses, newClasses);
18448             }
18449           }
18450           oldVal = shallowCopy(newVal);
18451         }
18452       }
18453     };
18454
18455     function arrayDifference(tokens1, tokens2) {
18456       var values = [];
18457
18458       outer:
18459       for(var i = 0; i < tokens1.length; i++) {
18460         var token = tokens1[i];
18461         for(var j = 0; j < tokens2.length; j++) {
18462           if(token == tokens2[j]) continue outer;
18463         }
18464         values.push(token);
18465       }
18466       return values;
18467     }
18468
18469     function arrayClasses (classVal) {
18470       if (isArray(classVal)) {
18471         return classVal;
18472       } else if (isString(classVal)) {
18473         return classVal.split(' ');
18474       } else if (isObject(classVal)) {
18475         var classes = [], i = 0;
18476         forEach(classVal, function(v, k) {
18477           if (v) {
18478             classes = classes.concat(k.split(' '));
18479           }
18480         });
18481         return classes;
18482       }
18483       return classVal;
18484     }
18485   }];
18486 }
18487
18488 /**
18489  * @ngdoc directive
18490  * @name ngClass
18491  * @restrict AC
18492  *
18493  * @description
18494  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18495  * an expression that represents all classes to be added.
18496  *
18497  * The directive operates in three different ways, depending on which of three types the expression
18498  * evaluates to:
18499  *
18500  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18501  * names.
18502  *
18503  * 2. If the expression evaluates to an array, each element of the array should be a string that is
18504  * one or more space-delimited class names.
18505  *
18506  * 3. If the expression evaluates to an object, then for each key-value pair of the
18507  * object with a truthy value the corresponding key is used as a class name.
18508  *
18509  * The directive won't add duplicate classes if a particular class was already set.
18510  *
18511  * When the expression changes, the previously added classes are removed and only then the
18512  * new classes are added.
18513  *
18514  * @animations
18515  * add - happens just before the class is applied to the element
18516  * remove - happens just before the class is removed from the element
18517  *
18518  * @element ANY
18519  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18520  *   of the evaluation can be a string representing space delimited class
18521  *   names, an array, or a map of class names to boolean values. In the case of a map, the
18522  *   names of the properties whose values are truthy will be added as css classes to the
18523  *   element.
18524  *
18525  * @example Example that demonstrates basic bindings via ngClass directive.
18526    <example>
18527      <file name="index.html">
18528        <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18529        <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18530        <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18531        <input type="checkbox" ng-model="error"> error (apply "red" class)
18532        <hr>
18533        <p ng-class="style">Using String Syntax</p>
18534        <input type="text" ng-model="style" placeholder="Type: bold strike red">
18535        <hr>
18536        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18537        <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18538        <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18539        <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18540      </file>
18541      <file name="style.css">
18542        .strike {
18543          text-decoration: line-through;
18544        }
18545        .bold {
18546            font-weight: bold;
18547        }
18548        .red {
18549            color: red;
18550        }
18551      </file>
18552      <file name="protractor.js" type="protractor">
18553        var ps = element.all(by.css('p'));
18554
18555        it('should let you toggle the class', function() {
18556
18557          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18558          expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18559
18560          element(by.model('important')).click();
18561          expect(ps.first().getAttribute('class')).toMatch(/bold/);
18562
18563          element(by.model('error')).click();
18564          expect(ps.first().getAttribute('class')).toMatch(/red/);
18565        });
18566
18567        it('should let you toggle string example', function() {
18568          expect(ps.get(1).getAttribute('class')).toBe('');
18569          element(by.model('style')).clear();
18570          element(by.model('style')).sendKeys('red');
18571          expect(ps.get(1).getAttribute('class')).toBe('red');
18572        });
18573
18574        it('array example should have 3 classes', function() {
18575          expect(ps.last().getAttribute('class')).toBe('');
18576          element(by.model('style1')).sendKeys('bold');
18577          element(by.model('style2')).sendKeys('strike');
18578          element(by.model('style3')).sendKeys('red');
18579          expect(ps.last().getAttribute('class')).toBe('bold strike red');
18580        });
18581      </file>
18582    </example>
18583
18584    ## Animations
18585
18586    The example below demonstrates how to perform animations using ngClass.
18587
18588    <example module="ngAnimate" deps="angular-animate.js" animations="true">
18589      <file name="index.html">
18590       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18591       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18592       <br>
18593       <span class="base-class" ng-class="myVar">Sample Text</span>
18594      </file>
18595      <file name="style.css">
18596        .base-class {
18597          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18598          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18599        }
18600
18601        .base-class.my-class {
18602          color: red;
18603          font-size:3em;
18604        }
18605      </file>
18606      <file name="protractor.js" type="protractor">
18607        it('should check ng-class', function() {
18608          expect(element(by.css('.base-class')).getAttribute('class')).not.
18609            toMatch(/my-class/);
18610
18611          element(by.id('setbtn')).click();
18612
18613          expect(element(by.css('.base-class')).getAttribute('class')).
18614            toMatch(/my-class/);
18615
18616          element(by.id('clearbtn')).click();
18617
18618          expect(element(by.css('.base-class')).getAttribute('class')).not.
18619            toMatch(/my-class/);
18620        });
18621      </file>
18622    </example>
18623
18624
18625    ## ngClass and pre-existing CSS3 Transitions/Animations
18626    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18627    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18628    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18629    to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18630    {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18631  */
18632 var ngClassDirective = classDirective('', true);
18633
18634 /**
18635  * @ngdoc directive
18636  * @name ngClassOdd
18637  * @restrict AC
18638  *
18639  * @description
18640  * The `ngClassOdd` and `ngClassEven` directives work exactly as
18641  * {@link ng.directive:ngClass ngClass}, except they work in
18642  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18643  *
18644  * This directive can be applied only within the scope of an
18645  * {@link ng.directive:ngRepeat ngRepeat}.
18646  *
18647  * @element ANY
18648  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18649  *   of the evaluation can be a string representing space delimited class names or an array.
18650  *
18651  * @example
18652    <example>
18653      <file name="index.html">
18654         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18655           <li ng-repeat="name in names">
18656            <span ng-class-odd="'odd'" ng-class-even="'even'">
18657              {{name}}
18658            </span>
18659           </li>
18660         </ol>
18661      </file>
18662      <file name="style.css">
18663        .odd {
18664          color: red;
18665        }
18666        .even {
18667          color: blue;
18668        }
18669      </file>
18670      <file name="protractor.js" type="protractor">
18671        it('should check ng-class-odd and ng-class-even', function() {
18672          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18673            toMatch(/odd/);
18674          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18675            toMatch(/even/);
18676        });
18677      </file>
18678    </example>
18679  */
18680 var ngClassOddDirective = classDirective('Odd', 0);
18681
18682 /**
18683  * @ngdoc directive
18684  * @name ngClassEven
18685  * @restrict AC
18686  *
18687  * @description
18688  * The `ngClassOdd` and `ngClassEven` directives work exactly as
18689  * {@link ng.directive:ngClass ngClass}, except they work in
18690  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18691  *
18692  * This directive can be applied only within the scope of an
18693  * {@link ng.directive:ngRepeat ngRepeat}.
18694  *
18695  * @element ANY
18696  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18697  *   result of the evaluation can be a string representing space delimited class names or an array.
18698  *
18699  * @example
18700    <example>
18701      <file name="index.html">
18702         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18703           <li ng-repeat="name in names">
18704            <span ng-class-odd="'odd'" ng-class-even="'even'">
18705              {{name}} &nbsp; &nbsp; &nbsp;
18706            </span>
18707           </li>
18708         </ol>
18709      </file>
18710      <file name="style.css">
18711        .odd {
18712          color: red;
18713        }
18714        .even {
18715          color: blue;
18716        }
18717      </file>
18718      <file name="protractor.js" type="protractor">
18719        it('should check ng-class-odd and ng-class-even', function() {
18720          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18721            toMatch(/odd/);
18722          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18723            toMatch(/even/);
18724        });
18725      </file>
18726    </example>
18727  */
18728 var ngClassEvenDirective = classDirective('Even', 1);
18729
18730 /**
18731  * @ngdoc directive
18732  * @name ngCloak
18733  * @restrict AC
18734  *
18735  * @description
18736  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18737  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18738  * directive to avoid the undesirable flicker effect caused by the html template display.
18739  *
18740  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18741  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18742  * of the browser view.
18743  *
18744  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18745  * `angular.min.js`.
18746  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18747  *
18748  * ```css
18749  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18750  *   display: none !important;
18751  * }
18752  * ```
18753  *
18754  * When this css rule is loaded by the browser, all html elements (including their children) that
18755  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18756  * during the compilation of the template it deletes the `ngCloak` element attribute, making
18757  * the compiled element visible.
18758  *
18759  * For the best result, the `angular.js` script must be loaded in the head section of the html
18760  * document; alternatively, the css rule above must be included in the external stylesheet of the
18761  * application.
18762  *
18763  * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
18764  * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18765  * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18766  *
18767  * @element ANY
18768  *
18769  * @example
18770    <example>
18771      <file name="index.html">
18772         <div id="template1" ng-cloak>{{ 'hello' }}</div>
18773         <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18774      </file>
18775      <file name="protractor.js" type="protractor">
18776        it('should remove the template directive and css class', function() {
18777          expect($('#template1').getAttribute('ng-cloak')).
18778            toBeNull();
18779          expect($('#template2').getAttribute('ng-cloak')).
18780            toBeNull();
18781        });
18782      </file>
18783    </example>
18784  *
18785  */
18786 var ngCloakDirective = ngDirective({
18787   compile: function(element, attr) {
18788     attr.$set('ngCloak', undefined);
18789     element.removeClass('ng-cloak');
18790   }
18791 });
18792
18793 /**
18794  * @ngdoc directive
18795  * @name ngController
18796  *
18797  * @description
18798  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18799  * supports the principles behind the Model-View-Controller design pattern.
18800  *
18801  * MVC components in angular:
18802  *
18803  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
18804  *   are accessed through bindings.
18805  * * View — The template (HTML with data bindings) that is rendered into the View.
18806  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18807  *   logic behind the application to decorate the scope with functions and values
18808  *
18809  * Note that you can also attach controllers to the DOM by declaring it in a route definition
18810  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18811  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18812  * and executed twice.
18813  *
18814  * @element ANY
18815  * @scope
18816  * @param {expression} ngController Name of a globally accessible constructor function or an
18817  *     {@link guide/expression expression} that on the current scope evaluates to a
18818  *     constructor function. The controller instance can be published into a scope property
18819  *     by specifying `as propertyName`.
18820  *
18821  * @example
18822  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18823  * greeting are methods declared on the controller (see source tab). These methods can
18824  * easily be called from the angular markup. Any changes to the data are automatically reflected
18825  * in the View without the need for a manual update.
18826  *
18827  * Two different declaration styles are included below:
18828  *
18829  * * one binds methods and properties directly onto the controller using `this`:
18830  * `ng-controller="SettingsController1 as settings"`
18831  * * one injects `$scope` into the controller:
18832  * `ng-controller="SettingsController2"`
18833  *
18834  * The second option is more common in the Angular community, and is generally used in boilerplates
18835  * and in this guide. However, there are advantages to binding properties directly to the controller
18836  * and avoiding scope.
18837  *
18838  * * Using `controller as` makes it obvious which controller you are accessing in the template when
18839  * multiple controllers apply to an element.
18840  * * If you are writing your controllers as classes you have easier access to the properties and
18841  * methods, which will appear on the scope, from inside the controller code.
18842  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
18843  * inheritance masking primitives.
18844  *
18845  * This example demonstrates the `controller as` syntax.
18846  *
18847  * <example name="ngControllerAs" module="controllerAsExample">
18848  *   <file name="index.html">
18849  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18850  *      Name: <input type="text" ng-model="settings.name"/>
18851  *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18852  *      Contact:
18853  *      <ul>
18854  *        <li ng-repeat="contact in settings.contacts">
18855  *          <select ng-model="contact.type">
18856  *             <option>phone</option>
18857  *             <option>email</option>
18858  *          </select>
18859  *          <input type="text" ng-model="contact.value"/>
18860  *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18861  *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18862  *        </li>
18863  *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18864  *     </ul>
18865  *    </div>
18866  *   </file>
18867  *   <file name="app.js">
18868  *    angular.module('controllerAsExample', [])
18869  *      .controller('SettingsController1', SettingsController1);
18870  *
18871  *    function SettingsController1() {
18872  *      this.name = "John Smith";
18873  *      this.contacts = [
18874  *        {type: 'phone', value: '408 555 1212'},
18875  *        {type: 'email', value: 'john.smith@example.org'} ];
18876  *    }
18877  *
18878  *    SettingsController1.prototype.greet = function() {
18879  *      alert(this.name);
18880  *    };
18881  *
18882  *    SettingsController1.prototype.addContact = function() {
18883  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
18884  *    };
18885  *
18886  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
18887  *     var index = this.contacts.indexOf(contactToRemove);
18888  *      this.contacts.splice(index, 1);
18889  *    };
18890  *
18891  *    SettingsController1.prototype.clearContact = function(contact) {
18892  *      contact.type = 'phone';
18893  *      contact.value = '';
18894  *    };
18895  *   </file>
18896  *   <file name="protractor.js" type="protractor">
18897  *     it('should check controller as', function() {
18898  *       var container = element(by.id('ctrl-as-exmpl'));
18899  *         expect(container.element(by.model('settings.name'))
18900  *           .getAttribute('value')).toBe('John Smith');
18901  *
18902  *       var firstRepeat =
18903  *           container.element(by.repeater('contact in settings.contacts').row(0));
18904  *       var secondRepeat =
18905  *           container.element(by.repeater('contact in settings.contacts').row(1));
18906  *
18907  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18908  *           .toBe('408 555 1212');
18909  *
18910  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
18911  *           .toBe('john.smith@example.org');
18912  *
18913  *       firstRepeat.element(by.linkText('clear')).click();
18914  *
18915  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18916  *           .toBe('');
18917  *
18918  *       container.element(by.linkText('add')).click();
18919  *
18920  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
18921  *           .element(by.model('contact.value'))
18922  *           .getAttribute('value'))
18923  *           .toBe('yourname@example.org');
18924  *     });
18925  *   </file>
18926  * </example>
18927  *
18928  * This example demonstrates the "attach to `$scope`" style of controller.
18929  *
18930  * <example name="ngController" module="controllerExample">
18931  *  <file name="index.html">
18932  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
18933  *     Name: <input type="text" ng-model="name"/>
18934  *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
18935  *     Contact:
18936  *     <ul>
18937  *       <li ng-repeat="contact in contacts">
18938  *         <select ng-model="contact.type">
18939  *            <option>phone</option>
18940  *            <option>email</option>
18941  *         </select>
18942  *         <input type="text" ng-model="contact.value"/>
18943  *         [ <a href="" ng-click="clearContact(contact)">clear</a>
18944  *         | <a href="" ng-click="removeContact(contact)">X</a> ]
18945  *       </li>
18946  *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18947  *    </ul>
18948  *   </div>
18949  *  </file>
18950  *  <file name="app.js">
18951  *   angular.module('controllerExample', [])
18952  *     .controller('SettingsController2', ['$scope', SettingsController2]);
18953  *
18954  *   function SettingsController2($scope) {
18955  *     $scope.name = "John Smith";
18956  *     $scope.contacts = [
18957  *       {type:'phone', value:'408 555 1212'},
18958  *       {type:'email', value:'john.smith@example.org'} ];
18959  *
18960  *     $scope.greet = function() {
18961  *       alert($scope.name);
18962  *     };
18963  *
18964  *     $scope.addContact = function() {
18965  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
18966  *     };
18967  *
18968  *     $scope.removeContact = function(contactToRemove) {
18969  *       var index = $scope.contacts.indexOf(contactToRemove);
18970  *       $scope.contacts.splice(index, 1);
18971  *     };
18972  *
18973  *     $scope.clearContact = function(contact) {
18974  *       contact.type = 'phone';
18975  *       contact.value = '';
18976  *     };
18977  *   }
18978  *  </file>
18979  *  <file name="protractor.js" type="protractor">
18980  *    it('should check controller', function() {
18981  *      var container = element(by.id('ctrl-exmpl'));
18982  *
18983  *      expect(container.element(by.model('name'))
18984  *          .getAttribute('value')).toBe('John Smith');
18985  *
18986  *      var firstRepeat =
18987  *          container.element(by.repeater('contact in contacts').row(0));
18988  *      var secondRepeat =
18989  *          container.element(by.repeater('contact in contacts').row(1));
18990  *
18991  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18992  *          .toBe('408 555 1212');
18993  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
18994  *          .toBe('john.smith@example.org');
18995  *
18996  *      firstRepeat.element(by.linkText('clear')).click();
18997  *
18998  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18999  *          .toBe('');
19000  *
19001  *      container.element(by.linkText('add')).click();
19002  *
19003  *      expect(container.element(by.repeater('contact in contacts').row(2))
19004  *          .element(by.model('contact.value'))
19005  *          .getAttribute('value'))
19006  *          .toBe('yourname@example.org');
19007  *    });
19008  *  </file>
19009  *</example>
19010
19011  */
19012 var ngControllerDirective = [function() {
19013   return {
19014     scope: true,
19015     controller: '@',
19016     priority: 500
19017   };
19018 }];
19019
19020 /**
19021  * @ngdoc directive
19022  * @name ngCsp
19023  *
19024  * @element html
19025  * @description
19026  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
19027  *
19028  * This is necessary when developing things like Google Chrome Extensions.
19029  *
19030  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
19031  * For Angular to be CSP compatible there are only two things that we need to do differently:
19032  *
19033  * - don't use `Function` constructor to generate optimized value getters
19034  * - don't inject custom stylesheet into the document
19035  *
19036  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
19037  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
19038  * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
19039  * be raised.
19040  *
19041  * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
19042  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
19043  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
19044  *
19045  * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
19046  * autodetection however triggers a CSP error to be logged in the console:
19047  *
19048  * ```
19049  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
19050  * script in the following Content Security Policy directive: "default-src 'self'". Note that
19051  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
19052  * ```
19053  *
19054  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
19055  * directive on the root element of the application or on the `angular.js` script tag, whichever
19056  * appears first in the html document.
19057  *
19058  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
19059  *
19060  * @example
19061  * This example shows how to apply the `ngCsp` directive to the `html` tag.
19062    ```html
19063      <!doctype html>
19064      <html ng-app ng-csp>
19065      ...
19066      ...
19067      </html>
19068    ```
19069  */
19070
19071 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
19072 // bootstrap the system (before $parse is instantiated), for this reason we just have
19073 // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
19074
19075 /**
19076  * @ngdoc directive
19077  * @name ngClick
19078  *
19079  * @description
19080  * The ngClick directive allows you to specify custom behavior when
19081  * an element is clicked.
19082  *
19083  * @element ANY
19084  * @priority 0
19085  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
19086  * click. ({@link guide/expression#-event- Event object is available as `$event`})
19087  *
19088  * @example
19089    <example>
19090      <file name="index.html">
19091       <button ng-click="count = count + 1" ng-init="count=0">
19092         Increment
19093       </button>
19094       <span>
19095         count: {{count}}
19096       <span>
19097      </file>
19098      <file name="protractor.js" type="protractor">
19099        it('should check ng-click', function() {
19100          expect(element(by.binding('count')).getText()).toMatch('0');
19101          element(by.css('button')).click();
19102          expect(element(by.binding('count')).getText()).toMatch('1');
19103        });
19104      </file>
19105    </example>
19106  */
19107 /*
19108  * A directive that allows creation of custom onclick handlers that are defined as angular
19109  * expressions and are compiled and executed within the current scope.
19110  *
19111  * Events that are handled via these handler are always configured not to propagate further.
19112  */
19113 var ngEventDirectives = {};
19114
19115 // For events that might fire synchronously during DOM manipulation
19116 // we need to execute their event handlers asynchronously using $evalAsync,
19117 // so that they are not executed in an inconsistent state.
19118 var forceAsyncEvents = {
19119   'blur': true,
19120   'focus': true
19121 };
19122 forEach(
19123   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
19124   function(eventName) {
19125     var directiveName = directiveNormalize('ng-' + eventName);
19126     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
19127       return {
19128         compile: function($element, attr) {
19129           var fn = $parse(attr[directiveName]);
19130           return function ngEventHandler(scope, element) {
19131             element.on(eventName, function(event) {
19132               var callback = function() {
19133                 fn(scope, {$event:event});
19134               };
19135               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
19136                 scope.$evalAsync(callback);
19137               } else {
19138                 scope.$apply(callback);
19139               }
19140             });
19141           };
19142         }
19143       };
19144     }];
19145   }
19146 );
19147
19148 /**
19149  * @ngdoc directive
19150  * @name ngDblclick
19151  *
19152  * @description
19153  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
19154  *
19155  * @element ANY
19156  * @priority 0
19157  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
19158  * a dblclick. (The Event object is available as `$event`)
19159  *
19160  * @example
19161    <example>
19162      <file name="index.html">
19163       <button ng-dblclick="count = count + 1" ng-init="count=0">
19164         Increment (on double click)
19165       </button>
19166       count: {{count}}
19167      </file>
19168    </example>
19169  */
19170
19171
19172 /**
19173  * @ngdoc directive
19174  * @name ngMousedown
19175  *
19176  * @description
19177  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
19178  *
19179  * @element ANY
19180  * @priority 0
19181  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
19182  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
19183  *
19184  * @example
19185    <example>
19186      <file name="index.html">
19187       <button ng-mousedown="count = count + 1" ng-init="count=0">
19188         Increment (on mouse down)
19189       </button>
19190       count: {{count}}
19191      </file>
19192    </example>
19193  */
19194
19195
19196 /**
19197  * @ngdoc directive
19198  * @name ngMouseup
19199  *
19200  * @description
19201  * Specify custom behavior on mouseup event.
19202  *
19203  * @element ANY
19204  * @priority 0
19205  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
19206  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
19207  *
19208  * @example
19209    <example>
19210      <file name="index.html">
19211       <button ng-mouseup="count = count + 1" ng-init="count=0">
19212         Increment (on mouse up)
19213       </button>
19214       count: {{count}}
19215      </file>
19216    </example>
19217  */
19218
19219 /**
19220  * @ngdoc directive
19221  * @name ngMouseover
19222  *
19223  * @description
19224  * Specify custom behavior on mouseover event.
19225  *
19226  * @element ANY
19227  * @priority 0
19228  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
19229  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
19230  *
19231  * @example
19232    <example>
19233      <file name="index.html">
19234       <button ng-mouseover="count = count + 1" ng-init="count=0">
19235         Increment (when mouse is over)
19236       </button>
19237       count: {{count}}
19238      </file>
19239    </example>
19240  */
19241
19242
19243 /**
19244  * @ngdoc directive
19245  * @name ngMouseenter
19246  *
19247  * @description
19248  * Specify custom behavior on mouseenter event.
19249  *
19250  * @element ANY
19251  * @priority 0
19252  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
19253  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
19254  *
19255  * @example
19256    <example>
19257      <file name="index.html">
19258       <button ng-mouseenter="count = count + 1" ng-init="count=0">
19259         Increment (when mouse enters)
19260       </button>
19261       count: {{count}}
19262      </file>
19263    </example>
19264  */
19265
19266
19267 /**
19268  * @ngdoc directive
19269  * @name ngMouseleave
19270  *
19271  * @description
19272  * Specify custom behavior on mouseleave event.
19273  *
19274  * @element ANY
19275  * @priority 0
19276  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
19277  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
19278  *
19279  * @example
19280    <example>
19281      <file name="index.html">
19282       <button ng-mouseleave="count = count + 1" ng-init="count=0">
19283         Increment (when mouse leaves)
19284       </button>
19285       count: {{count}}
19286      </file>
19287    </example>
19288  */
19289
19290
19291 /**
19292  * @ngdoc directive
19293  * @name ngMousemove
19294  *
19295  * @description
19296  * Specify custom behavior on mousemove event.
19297  *
19298  * @element ANY
19299  * @priority 0
19300  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
19301  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
19302  *
19303  * @example
19304    <example>
19305      <file name="index.html">
19306       <button ng-mousemove="count = count + 1" ng-init="count=0">
19307         Increment (when mouse moves)
19308       </button>
19309       count: {{count}}
19310      </file>
19311    </example>
19312  */
19313
19314
19315 /**
19316  * @ngdoc directive
19317  * @name ngKeydown
19318  *
19319  * @description
19320  * Specify custom behavior on keydown event.
19321  *
19322  * @element ANY
19323  * @priority 0
19324  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
19325  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19326  *
19327  * @example
19328    <example>
19329      <file name="index.html">
19330       <input ng-keydown="count = count + 1" ng-init="count=0">
19331       key down count: {{count}}
19332      </file>
19333    </example>
19334  */
19335
19336
19337 /**
19338  * @ngdoc directive
19339  * @name ngKeyup
19340  *
19341  * @description
19342  * Specify custom behavior on keyup event.
19343  *
19344  * @element ANY
19345  * @priority 0
19346  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
19347  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19348  *
19349  * @example
19350    <example>
19351      <file name="index.html">
19352        <p>Typing in the input box below updates the key count</p>
19353        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
19354
19355        <p>Typing in the input box below updates the keycode</p>
19356        <input ng-keyup="event=$event">
19357        <p>event keyCode: {{ event.keyCode }}</p>
19358        <p>event altKey: {{ event.altKey }}</p>
19359      </file>
19360    </example>
19361  */
19362
19363
19364 /**
19365  * @ngdoc directive
19366  * @name ngKeypress
19367  *
19368  * @description
19369  * Specify custom behavior on keypress event.
19370  *
19371  * @element ANY
19372  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
19373  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
19374  * and can be interrogated for keyCode, altKey, etc.)
19375  *
19376  * @example
19377    <example>
19378      <file name="index.html">
19379       <input ng-keypress="count = count + 1" ng-init="count=0">
19380       key press count: {{count}}
19381      </file>
19382    </example>
19383  */
19384
19385
19386 /**
19387  * @ngdoc directive
19388  * @name ngSubmit
19389  *
19390  * @description
19391  * Enables binding angular expressions to onsubmit events.
19392  *
19393  * Additionally it prevents the default action (which for form means sending the request to the
19394  * server and reloading the current page), but only if the form does not contain `action`,
19395  * `data-action`, or `x-action` attributes.
19396  *
19397  * <div class="alert alert-warning">
19398  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
19399  * `ngSubmit` handlers together. See the
19400  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
19401  * for a detailed discussion of when `ngSubmit` may be triggered.
19402  * </div>
19403  *
19404  * @element form
19405  * @priority 0
19406  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
19407  * ({@link guide/expression#-event- Event object is available as `$event`})
19408  *
19409  * @example
19410    <example module="submitExample">
19411      <file name="index.html">
19412       <script>
19413         angular.module('submitExample', [])
19414           .controller('ExampleController', ['$scope', function($scope) {
19415             $scope.list = [];
19416             $scope.text = 'hello';
19417             $scope.submit = function() {
19418               if ($scope.text) {
19419                 $scope.list.push(this.text);
19420                 $scope.text = '';
19421               }
19422             };
19423           }]);
19424       </script>
19425       <form ng-submit="submit()" ng-controller="ExampleController">
19426         Enter text and hit enter:
19427         <input type="text" ng-model="text" name="text" />
19428         <input type="submit" id="submit" value="Submit" />
19429         <pre>list={{list}}</pre>
19430       </form>
19431      </file>
19432      <file name="protractor.js" type="protractor">
19433        it('should check ng-submit', function() {
19434          expect(element(by.binding('list')).getText()).toBe('list=[]');
19435          element(by.css('#submit')).click();
19436          expect(element(by.binding('list')).getText()).toContain('hello');
19437          expect(element(by.model('text')).getAttribute('value')).toBe('');
19438        });
19439        it('should ignore empty strings', function() {
19440          expect(element(by.binding('list')).getText()).toBe('list=[]');
19441          element(by.css('#submit')).click();
19442          element(by.css('#submit')).click();
19443          expect(element(by.binding('list')).getText()).toContain('hello');
19444         });
19445      </file>
19446    </example>
19447  */
19448
19449 /**
19450  * @ngdoc directive
19451  * @name ngFocus
19452  *
19453  * @description
19454  * Specify custom behavior on focus event.
19455  *
19456  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
19457  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19458  * during an `$apply` to ensure a consistent state.
19459  *
19460  * @element window, input, select, textarea, a
19461  * @priority 0
19462  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
19463  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
19464  *
19465  * @example
19466  * See {@link ng.directive:ngClick ngClick}
19467  */
19468
19469 /**
19470  * @ngdoc directive
19471  * @name ngBlur
19472  *
19473  * @description
19474  * Specify custom behavior on blur event.
19475  *
19476  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
19477  * an element has lost focus.
19478  *
19479  * Note: As the `blur` event is executed synchronously also during DOM manipulations
19480  * (e.g. removing a focussed input),
19481  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19482  * during an `$apply` to ensure a consistent state.
19483  *
19484  * @element window, input, select, textarea, a
19485  * @priority 0
19486  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
19487  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
19488  *
19489  * @example
19490  * See {@link ng.directive:ngClick ngClick}
19491  */
19492
19493 /**
19494  * @ngdoc directive
19495  * @name ngCopy
19496  *
19497  * @description
19498  * Specify custom behavior on copy event.
19499  *
19500  * @element window, input, select, textarea, a
19501  * @priority 0
19502  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
19503  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
19504  *
19505  * @example
19506    <example>
19507      <file name="index.html">
19508       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
19509       copied: {{copied}}
19510      </file>
19511    </example>
19512  */
19513
19514 /**
19515  * @ngdoc directive
19516  * @name ngCut
19517  *
19518  * @description
19519  * Specify custom behavior on cut event.
19520  *
19521  * @element window, input, select, textarea, a
19522  * @priority 0
19523  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
19524  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
19525  *
19526  * @example
19527    <example>
19528      <file name="index.html">
19529       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
19530       cut: {{cut}}
19531      </file>
19532    </example>
19533  */
19534
19535 /**
19536  * @ngdoc directive
19537  * @name ngPaste
19538  *
19539  * @description
19540  * Specify custom behavior on paste event.
19541  *
19542  * @element window, input, select, textarea, a
19543  * @priority 0
19544  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19545  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19546  *
19547  * @example
19548    <example>
19549      <file name="index.html">
19550       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19551       pasted: {{paste}}
19552      </file>
19553    </example>
19554  */
19555
19556 /**
19557  * @ngdoc directive
19558  * @name ngIf
19559  * @restrict A
19560  *
19561  * @description
19562  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19563  * {expression}. If the expression assigned to `ngIf` evaluates to a false
19564  * value then the element is removed from the DOM, otherwise a clone of the
19565  * element is reinserted into the DOM.
19566  *
19567  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19568  * element in the DOM rather than changing its visibility via the `display` css property.  A common
19569  * case when this difference is significant is when using css selectors that rely on an element's
19570  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
19571  *
19572  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19573  * is created when the element is restored.  The scope created within `ngIf` inherits from
19574  * its parent scope using
19575  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
19576  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19577  * a javascript primitive defined in the parent scope. In this case any modifications made to the
19578  * variable within the child scope will override (hide) the value in the parent scope.
19579  *
19580  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19581  * is if an element's class attribute is directly modified after it's compiled, using something like
19582  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19583  * the added class will be lost because the original compiled state is used to regenerate the element.
19584  *
19585  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19586  * and `leave` effects.
19587  *
19588  * @animations
19589  * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
19590  * leave - happens just before the ngIf contents are removed from the DOM
19591  *
19592  * @element ANY
19593  * @scope
19594  * @priority 600
19595  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19596  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19597  *     element is added to the DOM tree.
19598  *
19599  * @example
19600   <example module="ngAnimate" deps="angular-animate.js" animations="true">
19601     <file name="index.html">
19602       Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19603       Show when checked:
19604       <span ng-if="checked" class="animate-if">
19605         I'm removed when the checkbox is unchecked.
19606       </span>
19607     </file>
19608     <file name="animations.css">
19609       .animate-if {
19610         background:white;
19611         border:1px solid black;
19612         padding:10px;
19613       }
19614
19615       .animate-if.ng-enter, .animate-if.ng-leave {
19616         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19617         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19618       }
19619
19620       .animate-if.ng-enter,
19621       .animate-if.ng-leave.ng-leave-active {
19622         opacity:0;
19623       }
19624
19625       .animate-if.ng-leave,
19626       .animate-if.ng-enter.ng-enter-active {
19627         opacity:1;
19628       }
19629     </file>
19630   </example>
19631  */
19632 var ngIfDirective = ['$animate', function($animate) {
19633   return {
19634     transclude: 'element',
19635     priority: 600,
19636     terminal: true,
19637     restrict: 'A',
19638     $$tlb: true,
19639     link: function ($scope, $element, $attr, ctrl, $transclude) {
19640         var block, childScope, previousElements;
19641         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19642
19643           if (toBoolean(value)) {
19644             if (!childScope) {
19645               childScope = $scope.$new();
19646               $transclude(childScope, function (clone) {
19647                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19648                 // Note: We only need the first/last node of the cloned nodes.
19649                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19650                 // by a directive with templateUrl when its template arrives.
19651                 block = {
19652                   clone: clone
19653                 };
19654                 $animate.enter(clone, $element.parent(), $element);
19655               });
19656             }
19657           } else {
19658             if(previousElements) {
19659               previousElements.remove();
19660               previousElements = null;
19661             }
19662             if(childScope) {
19663               childScope.$destroy();
19664               childScope = null;
19665             }
19666             if(block) {
19667               previousElements = getBlockElements(block.clone);
19668               $animate.leave(previousElements, function() {
19669                 previousElements = null;
19670               });
19671               block = null;
19672             }
19673           }
19674         });
19675     }
19676   };
19677 }];
19678
19679 /**
19680  * @ngdoc directive
19681  * @name ngInclude
19682  * @restrict ECA
19683  *
19684  * @description
19685  * Fetches, compiles and includes an external HTML fragment.
19686  *
19687  * By default, the template URL is restricted to the same domain and protocol as the
19688  * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19689  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19690  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19691  * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19692  * ng.$sce Strict Contextual Escaping}.
19693  *
19694  * In addition, the browser's
19695  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19696  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19697  * policy may further restrict whether the template is successfully loaded.
19698  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19699  * access on some browsers.
19700  *
19701  * @animations
19702  * enter - animation is used to bring new content into the browser.
19703  * leave - animation is used to animate existing content away.
19704  *
19705  * The enter and leave animation occur concurrently.
19706  *
19707  * @scope
19708  * @priority 400
19709  *
19710  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19711  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19712  * @param {string=} onload Expression to evaluate when a new partial is loaded.
19713  *
19714  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19715  *                  $anchorScroll} to scroll the viewport after the content is loaded.
19716  *
19717  *                  - If the attribute is not set, disable scrolling.
19718  *                  - If the attribute is set without value, enable scrolling.
19719  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19720  *
19721  * @example
19722   <example module="includeExample" deps="angular-animate.js" animations="true">
19723     <file name="index.html">
19724      <div ng-controller="ExampleController">
19725        <select ng-model="template" ng-options="t.name for t in templates">
19726         <option value="">(blank)</option>
19727        </select>
19728        url of the template: <tt>{{template.url}}</tt>
19729        <hr/>
19730        <div class="slide-animate-container">
19731          <div class="slide-animate" ng-include="template.url"></div>
19732        </div>
19733      </div>
19734     </file>
19735     <file name="script.js">
19736       angular.module('includeExample', ['ngAnimate'])
19737         .controller('ExampleController', ['$scope', function($scope) {
19738           $scope.templates =
19739             [ { name: 'template1.html', url: 'template1.html'},
19740               { name: 'template2.html', url: 'template2.html'} ];
19741           $scope.template = $scope.templates[0];
19742         }]);
19743      </file>
19744     <file name="template1.html">
19745       Content of template1.html
19746     </file>
19747     <file name="template2.html">
19748       Content of template2.html
19749     </file>
19750     <file name="animations.css">
19751       .slide-animate-container {
19752         position:relative;
19753         background:white;
19754         border:1px solid black;
19755         height:40px;
19756         overflow:hidden;
19757       }
19758
19759       .slide-animate {
19760         padding:10px;
19761       }
19762
19763       .slide-animate.ng-enter, .slide-animate.ng-leave {
19764         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19765         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19766
19767         position:absolute;
19768         top:0;
19769         left:0;
19770         right:0;
19771         bottom:0;
19772         display:block;
19773         padding:10px;
19774       }
19775
19776       .slide-animate.ng-enter {
19777         top:-50px;
19778       }
19779       .slide-animate.ng-enter.ng-enter-active {
19780         top:0;
19781       }
19782
19783       .slide-animate.ng-leave {
19784         top:0;
19785       }
19786       .slide-animate.ng-leave.ng-leave-active {
19787         top:50px;
19788       }
19789     </file>
19790     <file name="protractor.js" type="protractor">
19791       var templateSelect = element(by.model('template'));
19792       var includeElem = element(by.css('[ng-include]'));
19793
19794       it('should load template1.html', function() {
19795         expect(includeElem.getText()).toMatch(/Content of template1.html/);
19796       });
19797
19798       it('should load template2.html', function() {
19799         if (browser.params.browser == 'firefox') {
19800           // Firefox can't handle using selects
19801           // See https://github.com/angular/protractor/issues/480
19802           return;
19803         }
19804         templateSelect.click();
19805         templateSelect.all(by.css('option')).get(2).click();
19806         expect(includeElem.getText()).toMatch(/Content of template2.html/);
19807       });
19808
19809       it('should change to blank', function() {
19810         if (browser.params.browser == 'firefox') {
19811           // Firefox can't handle using selects
19812           return;
19813         }
19814         templateSelect.click();
19815         templateSelect.all(by.css('option')).get(0).click();
19816         expect(includeElem.isPresent()).toBe(false);
19817       });
19818     </file>
19819   </example>
19820  */
19821
19822
19823 /**
19824  * @ngdoc event
19825  * @name ngInclude#$includeContentRequested
19826  * @eventType emit on the scope ngInclude was declared in
19827  * @description
19828  * Emitted every time the ngInclude content is requested.
19829  */
19830
19831
19832 /**
19833  * @ngdoc event
19834  * @name ngInclude#$includeContentLoaded
19835  * @eventType emit on the current ngInclude scope
19836  * @description
19837  * Emitted every time the ngInclude content is reloaded.
19838  */
19839 var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
19840                   function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
19841   return {
19842     restrict: 'ECA',
19843     priority: 400,
19844     terminal: true,
19845     transclude: 'element',
19846     controller: angular.noop,
19847     compile: function(element, attr) {
19848       var srcExp = attr.ngInclude || attr.src,
19849           onloadExp = attr.onload || '',
19850           autoScrollExp = attr.autoscroll;
19851
19852       return function(scope, $element, $attr, ctrl, $transclude) {
19853         var changeCounter = 0,
19854             currentScope,
19855             previousElement,
19856             currentElement;
19857
19858         var cleanupLastIncludeContent = function() {
19859           if(previousElement) {
19860             previousElement.remove();
19861             previousElement = null;
19862           }
19863           if(currentScope) {
19864             currentScope.$destroy();
19865             currentScope = null;
19866           }
19867           if(currentElement) {
19868             $animate.leave(currentElement, function() {
19869               previousElement = null;
19870             });
19871             previousElement = currentElement;
19872             currentElement = null;
19873           }
19874         };
19875
19876         scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
19877           var afterAnimation = function() {
19878             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
19879               $anchorScroll();
19880             }
19881           };
19882           var thisChangeId = ++changeCounter;
19883
19884           if (src) {
19885             $http.get(src, {cache: $templateCache}).success(function(response) {
19886               if (thisChangeId !== changeCounter) return;
19887               var newScope = scope.$new();
19888               ctrl.template = response;
19889
19890               // Note: This will also link all children of ng-include that were contained in the original
19891               // html. If that content contains controllers, ... they could pollute/change the scope.
19892               // However, using ng-include on an element with additional content does not make sense...
19893               // Note: We can't remove them in the cloneAttchFn of $transclude as that
19894               // function is called before linking the content, which would apply child
19895               // directives to non existing elements.
19896               var clone = $transclude(newScope, function(clone) {
19897                 cleanupLastIncludeContent();
19898                 $animate.enter(clone, null, $element, afterAnimation);
19899               });
19900
19901               currentScope = newScope;
19902               currentElement = clone;
19903
19904               currentScope.$emit('$includeContentLoaded');
19905               scope.$eval(onloadExp);
19906             }).error(function() {
19907               if (thisChangeId === changeCounter) cleanupLastIncludeContent();
19908             });
19909             scope.$emit('$includeContentRequested');
19910           } else {
19911             cleanupLastIncludeContent();
19912             ctrl.template = null;
19913           }
19914         });
19915       };
19916     }
19917   };
19918 }];
19919
19920 // This directive is called during the $transclude call of the first `ngInclude` directive.
19921 // It will replace and compile the content of the element with the loaded template.
19922 // We need this directive so that the element content is already filled when
19923 // the link function of another directive on the same element as ngInclude
19924 // is called.
19925 var ngIncludeFillContentDirective = ['$compile',
19926   function($compile) {
19927     return {
19928       restrict: 'ECA',
19929       priority: -400,
19930       require: 'ngInclude',
19931       link: function(scope, $element, $attr, ctrl) {
19932         $element.html(ctrl.template);
19933         $compile($element.contents())(scope);
19934       }
19935     };
19936   }];
19937
19938 /**
19939  * @ngdoc directive
19940  * @name ngInit
19941  * @restrict AC
19942  *
19943  * @description
19944  * The `ngInit` directive allows you to evaluate an expression in the
19945  * current scope.
19946  *
19947  * <div class="alert alert-error">
19948  * The only appropriate use of `ngInit` is for aliasing special properties of
19949  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
19950  * should use {@link guide/controller controllers} rather than `ngInit`
19951  * to initialize values on a scope.
19952  * </div>
19953  * <div class="alert alert-warning">
19954  * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
19955  * sure you have parenthesis for correct precedence:
19956  * <pre class="prettyprint">
19957  *   <div ng-init="test1 = (data | orderBy:'name')"></div>
19958  * </pre>
19959  * </div>
19960  *
19961  * @priority 450
19962  *
19963  * @element ANY
19964  * @param {expression} ngInit {@link guide/expression Expression} to eval.
19965  *
19966  * @example
19967    <example module="initExample">
19968      <file name="index.html">
19969    <script>
19970      angular.module('initExample', [])
19971        .controller('ExampleController', ['$scope', function($scope) {
19972          $scope.list = [['a', 'b'], ['c', 'd']];
19973        }]);
19974    </script>
19975    <div ng-controller="ExampleController">
19976      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
19977        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
19978           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
19979        </div>
19980      </div>
19981    </div>
19982      </file>
19983      <file name="protractor.js" type="protractor">
19984        it('should alias index positions', function() {
19985          var elements = element.all(by.css('.example-init'));
19986          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
19987          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
19988          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
19989          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
19990        });
19991      </file>
19992    </example>
19993  */
19994 var ngInitDirective = ngDirective({
19995   priority: 450,
19996   compile: function() {
19997     return {
19998       pre: function(scope, element, attrs) {
19999         scope.$eval(attrs.ngInit);
20000       }
20001     };
20002   }
20003 });
20004
20005 /**
20006  * @ngdoc directive
20007  * @name ngNonBindable
20008  * @restrict AC
20009  * @priority 1000
20010  *
20011  * @description
20012  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
20013  * DOM element. This is useful if the element contains what appears to be Angular directives and
20014  * bindings but which should be ignored by Angular. This could be the case if you have a site that
20015  * displays snippets of code, for instance.
20016  *
20017  * @element ANY
20018  *
20019  * @example
20020  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
20021  * but the one wrapped in `ngNonBindable` is left alone.
20022  *
20023  * @example
20024     <example>
20025       <file name="index.html">
20026         <div>Normal: {{1 + 2}}</div>
20027         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
20028       </file>
20029       <file name="protractor.js" type="protractor">
20030        it('should check ng-non-bindable', function() {
20031          expect(element(by.binding('1 + 2')).getText()).toContain('3');
20032          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
20033        });
20034       </file>
20035     </example>
20036  */
20037 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
20038
20039 /**
20040  * @ngdoc directive
20041  * @name ngPluralize
20042  * @restrict EA
20043  *
20044  * @description
20045  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
20046  * These rules are bundled with angular.js, but can be overridden
20047  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
20048  * by specifying the mappings between
20049  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
20050  * and the strings to be displayed.
20051  *
20052  * # Plural categories and explicit number rules
20053  * There are two
20054  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
20055  * in Angular's default en-US locale: "one" and "other".
20056  *
20057  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
20058  * any number that is not 1), an explicit number rule can only match one number. For example, the
20059  * explicit number rule for "3" matches the number 3. There are examples of plural categories
20060  * and explicit number rules throughout the rest of this documentation.
20061  *
20062  * # Configuring ngPluralize
20063  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
20064  * You can also provide an optional attribute, `offset`.
20065  *
20066  * The value of the `count` attribute can be either a string or an {@link guide/expression
20067  * Angular expression}; these are evaluated on the current scope for its bound value.
20068  *
20069  * The `when` attribute specifies the mappings between plural categories and the actual
20070  * string to be displayed. The value of the attribute should be a JSON object.
20071  *
20072  * The following example shows how to configure ngPluralize:
20073  *
20074  * ```html
20075  * <ng-pluralize count="personCount"
20076                  when="{'0': 'Nobody is viewing.',
20077  *                      'one': '1 person is viewing.',
20078  *                      'other': '{} people are viewing.'}">
20079  * </ng-pluralize>
20080  *```
20081  *
20082  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
20083  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
20084  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
20085  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
20086  * show "a dozen people are viewing".
20087  *
20088  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
20089  * into pluralized strings. In the previous example, Angular will replace `{}` with
20090  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
20091  * for <span ng-non-bindable>{{numberExpression}}</span>.
20092  *
20093  * # Configuring ngPluralize with offset
20094  * The `offset` attribute allows further customization of pluralized text, which can result in
20095  * a better user experience. For example, instead of the message "4 people are viewing this document",
20096  * you might display "John, Kate and 2 others are viewing this document".
20097  * The offset attribute allows you to offset a number by any desired value.
20098  * Let's take a look at an example:
20099  *
20100  * ```html
20101  * <ng-pluralize count="personCount" offset=2
20102  *               when="{'0': 'Nobody is viewing.',
20103  *                      '1': '{{person1}} is viewing.',
20104  *                      '2': '{{person1}} and {{person2}} are viewing.',
20105  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
20106  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20107  * </ng-pluralize>
20108  * ```
20109  *
20110  * Notice that we are still using two plural categories(one, other), but we added
20111  * three explicit number rules 0, 1 and 2.
20112  * When one person, perhaps John, views the document, "John is viewing" will be shown.
20113  * When three people view the document, no explicit number rule is found, so
20114  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
20115  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
20116  * is shown.
20117  *
20118  * Note that when you specify offsets, you must provide explicit number rules for
20119  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
20120  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
20121  * plural categories "one" and "other".
20122  *
20123  * @param {string|expression} count The variable to be bound to.
20124  * @param {string} when The mapping between plural category to its corresponding strings.
20125  * @param {number=} offset Offset to deduct from the total number.
20126  *
20127  * @example
20128     <example module="pluralizeExample">
20129       <file name="index.html">
20130         <script>
20131           angular.module('pluralizeExample', [])
20132             .controller('ExampleController', ['$scope', function($scope) {
20133               $scope.person1 = 'Igor';
20134               $scope.person2 = 'Misko';
20135               $scope.personCount = 1;
20136             }]);
20137         </script>
20138         <div ng-controller="ExampleController">
20139           Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
20140           Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
20141           Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
20142
20143           <!--- Example with simple pluralization rules for en locale --->
20144           Without Offset:
20145           <ng-pluralize count="personCount"
20146                         when="{'0': 'Nobody is viewing.',
20147                                'one': '1 person is viewing.',
20148                                'other': '{} people are viewing.'}">
20149           </ng-pluralize><br>
20150
20151           <!--- Example with offset --->
20152           With Offset(2):
20153           <ng-pluralize count="personCount" offset=2
20154                         when="{'0': 'Nobody is viewing.',
20155                                '1': '{{person1}} is viewing.',
20156                                '2': '{{person1}} and {{person2}} are viewing.',
20157                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
20158                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20159           </ng-pluralize>
20160         </div>
20161       </file>
20162       <file name="protractor.js" type="protractor">
20163         it('should show correct pluralized string', function() {
20164           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
20165           var withOffset = element.all(by.css('ng-pluralize')).get(1);
20166           var countInput = element(by.model('personCount'));
20167
20168           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
20169           expect(withOffset.getText()).toEqual('Igor is viewing.');
20170
20171           countInput.clear();
20172           countInput.sendKeys('0');
20173
20174           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
20175           expect(withOffset.getText()).toEqual('Nobody is viewing.');
20176
20177           countInput.clear();
20178           countInput.sendKeys('2');
20179
20180           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
20181           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
20182
20183           countInput.clear();
20184           countInput.sendKeys('3');
20185
20186           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
20187           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
20188
20189           countInput.clear();
20190           countInput.sendKeys('4');
20191
20192           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
20193           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
20194         });
20195         it('should show data-bound names', function() {
20196           var withOffset = element.all(by.css('ng-pluralize')).get(1);
20197           var personCount = element(by.model('personCount'));
20198           var person1 = element(by.model('person1'));
20199           var person2 = element(by.model('person2'));
20200           personCount.clear();
20201           personCount.sendKeys('4');
20202           person1.clear();
20203           person1.sendKeys('Di');
20204           person2.clear();
20205           person2.sendKeys('Vojta');
20206           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
20207         });
20208       </file>
20209     </example>
20210  */
20211 var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
20212   var BRACE = /{}/g;
20213   return {
20214     restrict: 'EA',
20215     link: function(scope, element, attr) {
20216       var numberExp = attr.count,
20217           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
20218           offset = attr.offset || 0,
20219           whens = scope.$eval(whenExp) || {},
20220           whensExpFns = {},
20221           startSymbol = $interpolate.startSymbol(),
20222           endSymbol = $interpolate.endSymbol(),
20223           isWhen = /^when(Minus)?(.+)$/;
20224
20225       forEach(attr, function(expression, attributeName) {
20226         if (isWhen.test(attributeName)) {
20227           whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
20228             element.attr(attr.$attr[attributeName]);
20229         }
20230       });
20231       forEach(whens, function(expression, key) {
20232         whensExpFns[key] =
20233           $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
20234             offset + endSymbol));
20235       });
20236
20237       scope.$watch(function ngPluralizeWatch() {
20238         var value = parseFloat(scope.$eval(numberExp));
20239
20240         if (!isNaN(value)) {
20241           //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
20242           //check it against pluralization rules in $locale service
20243           if (!(value in whens)) value = $locale.pluralCat(value - offset);
20244            return whensExpFns[value](scope, element, true);
20245         } else {
20246           return '';
20247         }
20248       }, function ngPluralizeWatchAction(newVal) {
20249         element.text(newVal);
20250       });
20251     }
20252   };
20253 }];
20254
20255 /**
20256  * @ngdoc directive
20257  * @name ngRepeat
20258  *
20259  * @description
20260  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
20261  * instance gets its own scope, where the given loop variable is set to the current collection item,
20262  * and `$index` is set to the item index or key.
20263  *
20264  * Special properties are exposed on the local scope of each template instance, including:
20265  *
20266  * | Variable  | Type            | Details                                                                     |
20267  * |-----------|-----------------|-----------------------------------------------------------------------------|
20268  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
20269  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
20270  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
20271  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
20272  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
20273  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
20274  *
20275  * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
20276  * This may be useful when, for instance, nesting ngRepeats.
20277  *
20278  * # Special repeat start and end points
20279  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
20280  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
20281  * 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)
20282  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
20283  *
20284  * The example below makes use of this feature:
20285  * ```html
20286  *   <header ng-repeat-start="item in items">
20287  *     Header {{ item }}
20288  *   </header>
20289  *   <div class="body">
20290  *     Body {{ item }}
20291  *   </div>
20292  *   <footer ng-repeat-end>
20293  *     Footer {{ item }}
20294  *   </footer>
20295  * ```
20296  *
20297  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
20298  * ```html
20299  *   <header>
20300  *     Header A
20301  *   </header>
20302  *   <div class="body">
20303  *     Body A
20304  *   </div>
20305  *   <footer>
20306  *     Footer A
20307  *   </footer>
20308  *   <header>
20309  *     Header B
20310  *   </header>
20311  *   <div class="body">
20312  *     Body B
20313  *   </div>
20314  *   <footer>
20315  *     Footer B
20316  *   </footer>
20317  * ```
20318  *
20319  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
20320  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
20321  *
20322  * @animations
20323  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
20324  *
20325  * **.leave** - when an item is removed from the list or when an item is filtered out
20326  *
20327  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
20328  *
20329  * @element ANY
20330  * @scope
20331  * @priority 1000
20332  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
20333  *   formats are currently supported:
20334  *
20335  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
20336  *     is a scope expression giving the collection to enumerate.
20337  *
20338  *     For example: `album in artist.albums`.
20339  *
20340  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
20341  *     and `expression` is the scope expression giving the collection to enumerate.
20342  *
20343  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
20344  *
20345  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
20346  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
20347  *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
20348  *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
20349  *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
20350  *     before specifying a tracking expression.
20351  *
20352  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
20353  *     will be associated by item identity in the array.
20354  *
20355  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
20356  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
20357  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
20358  *     element in the same way in the DOM.
20359  *
20360  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
20361  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
20362  *     property is same.
20363  *
20364  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
20365  *     to items in conjunction with a tracking expression.
20366  *
20367  * @example
20368  * This example initializes the scope to a list of names and
20369  * then uses `ngRepeat` to display every person:
20370   <example module="ngAnimate" deps="angular-animate.js" animations="true">
20371     <file name="index.html">
20372       <div ng-init="friends = [
20373         {name:'John', age:25, gender:'boy'},
20374         {name:'Jessie', age:30, gender:'girl'},
20375         {name:'Johanna', age:28, gender:'girl'},
20376         {name:'Joy', age:15, gender:'girl'},
20377         {name:'Mary', age:28, gender:'girl'},
20378         {name:'Peter', age:95, gender:'boy'},
20379         {name:'Sebastian', age:50, gender:'boy'},
20380         {name:'Erika', age:27, gender:'girl'},
20381         {name:'Patrick', age:40, gender:'boy'},
20382         {name:'Samantha', age:60, gender:'girl'}
20383       ]">
20384         I have {{friends.length}} friends. They are:
20385         <input type="search" ng-model="q" placeholder="filter friends..." />
20386         <ul class="example-animate-container">
20387           <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
20388             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
20389           </li>
20390         </ul>
20391       </div>
20392     </file>
20393     <file name="animations.css">
20394       .example-animate-container {
20395         background:white;
20396         border:1px solid black;
20397         list-style:none;
20398         margin:0;
20399         padding:0 10px;
20400       }
20401
20402       .animate-repeat {
20403         line-height:40px;
20404         list-style:none;
20405         box-sizing:border-box;
20406       }
20407
20408       .animate-repeat.ng-move,
20409       .animate-repeat.ng-enter,
20410       .animate-repeat.ng-leave {
20411         -webkit-transition:all linear 0.5s;
20412         transition:all linear 0.5s;
20413       }
20414
20415       .animate-repeat.ng-leave.ng-leave-active,
20416       .animate-repeat.ng-move,
20417       .animate-repeat.ng-enter {
20418         opacity:0;
20419         max-height:0;
20420       }
20421
20422       .animate-repeat.ng-leave,
20423       .animate-repeat.ng-move.ng-move-active,
20424       .animate-repeat.ng-enter.ng-enter-active {
20425         opacity:1;
20426         max-height:40px;
20427       }
20428     </file>
20429     <file name="protractor.js" type="protractor">
20430       var friends = element.all(by.repeater('friend in friends'));
20431
20432       it('should render initial data set', function() {
20433         expect(friends.count()).toBe(10);
20434         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
20435         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
20436         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
20437         expect(element(by.binding('friends.length')).getText())
20438             .toMatch("I have 10 friends. They are:");
20439       });
20440
20441        it('should update repeater when filter predicate changes', function() {
20442          expect(friends.count()).toBe(10);
20443
20444          element(by.model('q')).sendKeys('ma');
20445
20446          expect(friends.count()).toBe(2);
20447          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
20448          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
20449        });
20450       </file>
20451     </example>
20452  */
20453 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20454   var NG_REMOVED = '$$NG_REMOVED';
20455   var ngRepeatMinErr = minErr('ngRepeat');
20456   return {
20457     transclude: 'element',
20458     priority: 1000,
20459     terminal: true,
20460     $$tlb: true,
20461     link: function($scope, $element, $attr, ctrl, $transclude){
20462         var expression = $attr.ngRepeat;
20463         var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
20464           trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
20465           lhs, rhs, valueIdentifier, keyIdentifier,
20466           hashFnLocals = {$id: hashKey};
20467
20468         if (!match) {
20469           throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
20470             expression);
20471         }
20472
20473         lhs = match[1];
20474         rhs = match[2];
20475         trackByExp = match[3];
20476
20477         if (trackByExp) {
20478           trackByExpGetter = $parse(trackByExp);
20479           trackByIdExpFn = function(key, value, index) {
20480             // assign key, value, and $index to the locals so that they can be used in hash functions
20481             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
20482             hashFnLocals[valueIdentifier] = value;
20483             hashFnLocals.$index = index;
20484             return trackByExpGetter($scope, hashFnLocals);
20485           };
20486         } else {
20487           trackByIdArrayFn = function(key, value) {
20488             return hashKey(value);
20489           };
20490           trackByIdObjFn = function(key) {
20491             return key;
20492           };
20493         }
20494
20495         match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
20496         if (!match) {
20497           throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
20498                                                                     lhs);
20499         }
20500         valueIdentifier = match[3] || match[1];
20501         keyIdentifier = match[2];
20502
20503         // Store a list of elements from previous run. This is a hash where key is the item from the
20504         // iterator, and the value is objects with following properties.
20505         //   - scope: bound scope
20506         //   - element: previous element.
20507         //   - index: position
20508         var lastBlockMap = {};
20509
20510         //watch props
20511         $scope.$watchCollection(rhs, function ngRepeatAction(collection){
20512           var index, length,
20513               previousNode = $element[0],     // current position of the node
20514               nextNode,
20515               // Same as lastBlockMap but it has the current state. It will become the
20516               // lastBlockMap on the next iteration.
20517               nextBlockMap = {},
20518               arrayLength,
20519               childScope,
20520               key, value, // key/value of iteration
20521               trackById,
20522               trackByIdFn,
20523               collectionKeys,
20524               block,       // last object information {scope, element, id}
20525               nextBlockOrder = [],
20526               elementsToRemove;
20527
20528
20529           if (isArrayLike(collection)) {
20530             collectionKeys = collection;
20531             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
20532           } else {
20533             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
20534             // if object, extract keys, sort them and use to determine order of iteration over obj props
20535             collectionKeys = [];
20536             for (key in collection) {
20537               if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
20538                 collectionKeys.push(key);
20539               }
20540             }
20541             collectionKeys.sort();
20542           }
20543
20544           arrayLength = collectionKeys.length;
20545
20546           // locate existing items
20547           length = nextBlockOrder.length = collectionKeys.length;
20548           for(index = 0; index < length; index++) {
20549            key = (collection === collectionKeys) ? index : collectionKeys[index];
20550            value = collection[key];
20551            trackById = trackByIdFn(key, value, index);
20552            assertNotHasOwnProperty(trackById, '`track by` id');
20553            if(lastBlockMap.hasOwnProperty(trackById)) {
20554              block = lastBlockMap[trackById];
20555              delete lastBlockMap[trackById];
20556              nextBlockMap[trackById] = block;
20557              nextBlockOrder[index] = block;
20558            } else if (nextBlockMap.hasOwnProperty(trackById)) {
20559              // restore lastBlockMap
20560              forEach(nextBlockOrder, function(block) {
20561                if (block && block.scope) lastBlockMap[block.id] = block;
20562              });
20563              // This is a duplicate and we need to throw an error
20564              throw ngRepeatMinErr('dupes',
20565                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
20566                   expression, trackById, toJson(value));
20567            } else {
20568              // new never before seen block
20569              nextBlockOrder[index] = { id: trackById };
20570              nextBlockMap[trackById] = false;
20571            }
20572          }
20573
20574           // remove existing items
20575           for (key in lastBlockMap) {
20576             // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20577             if (lastBlockMap.hasOwnProperty(key)) {
20578               block = lastBlockMap[key];
20579               elementsToRemove = getBlockElements(block.clone);
20580               $animate.leave(elementsToRemove);
20581               forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
20582               block.scope.$destroy();
20583             }
20584           }
20585
20586           // we are not using forEach for perf reasons (trying to avoid #call)
20587           for (index = 0, length = collectionKeys.length; index < length; index++) {
20588             key = (collection === collectionKeys) ? index : collectionKeys[index];
20589             value = collection[key];
20590             block = nextBlockOrder[index];
20591             if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20592
20593             if (block.scope) {
20594               // if we have already seen this object, then we need to reuse the
20595               // associated scope/element
20596               childScope = block.scope;
20597
20598               nextNode = previousNode;
20599               do {
20600                 nextNode = nextNode.nextSibling;
20601               } while(nextNode && nextNode[NG_REMOVED]);
20602
20603               if (getBlockStart(block) != nextNode) {
20604                 // existing item which got moved
20605                 $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20606               }
20607               previousNode = getBlockEnd(block);
20608             } else {
20609               // new item which we don't know about
20610               childScope = $scope.$new();
20611             }
20612
20613             childScope[valueIdentifier] = value;
20614             if (keyIdentifier) childScope[keyIdentifier] = key;
20615             childScope.$index = index;
20616             childScope.$first = (index === 0);
20617             childScope.$last = (index === (arrayLength - 1));
20618             childScope.$middle = !(childScope.$first || childScope.$last);
20619             // jshint bitwise: false
20620             childScope.$odd = !(childScope.$even = (index&1) === 0);
20621             // jshint bitwise: true
20622
20623             if (!block.scope) {
20624               $transclude(childScope, function(clone) {
20625                 clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20626                 $animate.enter(clone, null, jqLite(previousNode));
20627                 previousNode = clone;
20628                 block.scope = childScope;
20629                 // Note: We only need the first/last node of the cloned nodes.
20630                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20631                 // by a directive with templateUrl when its template arrives.
20632                 block.clone = clone;
20633                 nextBlockMap[block.id] = block;
20634               });
20635             }
20636           }
20637           lastBlockMap = nextBlockMap;
20638         });
20639     }
20640   };
20641
20642   function getBlockStart(block) {
20643     return block.clone[0];
20644   }
20645
20646   function getBlockEnd(block) {
20647     return block.clone[block.clone.length - 1];
20648   }
20649 }];
20650
20651 /**
20652  * @ngdoc directive
20653  * @name ngShow
20654  *
20655  * @description
20656  * The `ngShow` directive shows or hides the given HTML element based on the expression
20657  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
20658  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20659  * in AngularJS and sets the display style to none (using an !important flag).
20660  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20661  *
20662  * ```html
20663  * <!-- when $scope.myValue is truthy (element is visible) -->
20664  * <div ng-show="myValue"></div>
20665  *
20666  * <!-- when $scope.myValue is falsy (element is hidden) -->
20667  * <div ng-show="myValue" class="ng-hide"></div>
20668  * ```
20669  *
20670  * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
20671  * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
20672  * from the element causing the element not to appear hidden.
20673  *
20674  * <div class="alert alert-warning">
20675  * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20676  * "f" / "0" / "false" / "no" / "n" / "[]"
20677  * </div>
20678  *
20679  * ## Why is !important used?
20680  *
20681  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
20682  * can be easily overridden by heavier selectors. For example, something as simple
20683  * as changing the display style on a HTML list item would make hidden elements appear visible.
20684  * This also becomes a bigger issue when dealing with CSS frameworks.
20685  *
20686  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20687  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20688  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20689  *
20690  * ### Overriding `.ng-hide`
20691  *
20692  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20693  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20694  * class in CSS:
20695  *
20696  * ```css
20697  * .ng-hide {
20698  *   //this is just another form of hiding an element
20699  *   display:block!important;
20700  *   position:absolute;
20701  *   top:-9999px;
20702  *   left:-9999px;
20703  * }
20704  * ```
20705  *
20706  * By default you don't need to override in CSS anything and the animations will work around the display style.
20707  *
20708  * ## A note about animations with `ngShow`
20709  *
20710  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20711  * is true and false. This system works like the animation system present with ngClass except that
20712  * you must also include the !important flag to override the display property
20713  * so that you can perform an animation when the element is hidden during the time of the animation.
20714  *
20715  * ```css
20716  * //
20717  * //a working example can be found at the bottom of this page
20718  * //
20719  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20720  *   transition:0.5s linear all;
20721  * }
20722  *
20723  * .my-element.ng-hide-add { ... }
20724  * .my-element.ng-hide-add.ng-hide-add-active { ... }
20725  * .my-element.ng-hide-remove { ... }
20726  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20727  * ```
20728  *
20729  * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
20730  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20731  *
20732  * @animations
20733  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
20734  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
20735  *
20736  * @element ANY
20737  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20738  *     then the element is shown or hidden respectively.
20739  *
20740  * @example
20741   <example module="ngAnimate" deps="angular-animate.js" animations="true">
20742     <file name="index.html">
20743       Click me: <input type="checkbox" ng-model="checked"><br/>
20744       <div>
20745         Show:
20746         <div class="check-element animate-show" ng-show="checked">
20747           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20748         </div>
20749       </div>
20750       <div>
20751         Hide:
20752         <div class="check-element animate-show" ng-hide="checked">
20753           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20754         </div>
20755       </div>
20756     </file>
20757     <file name="glyphicons.css">
20758       @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20759     </file>
20760     <file name="animations.css">
20761       .animate-show {
20762         -webkit-transition:all linear 0.5s;
20763         transition:all linear 0.5s;
20764         line-height:20px;
20765         opacity:1;
20766         padding:10px;
20767         border:1px solid black;
20768         background:white;
20769       }
20770
20771       .animate-show.ng-hide {
20772         line-height:0;
20773         opacity:0;
20774         padding:0 10px;
20775       }
20776
20777       .check-element {
20778         padding:10px;
20779         border:1px solid black;
20780         background:white;
20781       }
20782     </file>
20783     <file name="protractor.js" type="protractor">
20784       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20785       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20786
20787       it('should check ng-show / ng-hide', function() {
20788         expect(thumbsUp.isDisplayed()).toBeFalsy();
20789         expect(thumbsDown.isDisplayed()).toBeTruthy();
20790
20791         element(by.model('checked')).click();
20792
20793         expect(thumbsUp.isDisplayed()).toBeTruthy();
20794         expect(thumbsDown.isDisplayed()).toBeFalsy();
20795       });
20796     </file>
20797   </example>
20798  */
20799 var ngShowDirective = ['$animate', function($animate) {
20800   return function(scope, element, attr) {
20801     scope.$watch(attr.ngShow, function ngShowWatchAction(value){
20802       $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20803     });
20804   };
20805 }];
20806
20807
20808 /**
20809  * @ngdoc directive
20810  * @name ngHide
20811  *
20812  * @description
20813  * The `ngHide` directive shows or hides the given HTML element based on the expression
20814  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
20815  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20816  * in AngularJS and sets the display style to none (using an !important flag).
20817  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20818  *
20819  * ```html
20820  * <!-- when $scope.myValue is truthy (element is hidden) -->
20821  * <div ng-hide="myValue" class="ng-hide"></div>
20822  *
20823  * <!-- when $scope.myValue is falsy (element is visible) -->
20824  * <div ng-hide="myValue"></div>
20825  * ```
20826  *
20827  * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
20828  * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
20829  * from the element causing the element not to appear hidden.
20830  *
20831  * <div class="alert alert-warning">
20832  * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20833  * "f" / "0" / "false" / "no" / "n" / "[]"
20834  * </div>
20835  *
20836  * ## Why is !important used?
20837  *
20838  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
20839  * can be easily overridden by heavier selectors. For example, something as simple
20840  * as changing the display style on a HTML list item would make hidden elements appear visible.
20841  * This also becomes a bigger issue when dealing with CSS frameworks.
20842  *
20843  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20844  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20845  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20846  *
20847  * ### Overriding `.ng-hide`
20848  *
20849  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20850  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20851  * class in CSS:
20852  *
20853  * ```css
20854  * .ng-hide {
20855  *   //this is just another form of hiding an element
20856  *   display:block!important;
20857  *   position:absolute;
20858  *   top:-9999px;
20859  *   left:-9999px;
20860  * }
20861  * ```
20862  *
20863  * By default you don't need to override in CSS anything and the animations will work around the display style.
20864  *
20865  * ## A note about animations with `ngHide`
20866  *
20867  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20868  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
20869  * CSS class is added and removed for you instead of your own CSS class.
20870  *
20871  * ```css
20872  * //
20873  * //a working example can be found at the bottom of this page
20874  * //
20875  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20876  *   transition:0.5s linear all;
20877  * }
20878  *
20879  * .my-element.ng-hide-add { ... }
20880  * .my-element.ng-hide-add.ng-hide-add-active { ... }
20881  * .my-element.ng-hide-remove { ... }
20882  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20883  * ```
20884  *
20885  * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display
20886  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20887  *
20888  * @animations
20889  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
20890  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
20891  *
20892  * @element ANY
20893  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
20894  *     the element is shown or hidden respectively.
20895  *
20896  * @example
20897   <example module="ngAnimate" deps="angular-animate.js" animations="true">
20898     <file name="index.html">
20899       Click me: <input type="checkbox" ng-model="checked"><br/>
20900       <div>
20901         Show:
20902         <div class="check-element animate-hide" ng-show="checked">
20903           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20904         </div>
20905       </div>
20906       <div>
20907         Hide:
20908         <div class="check-element animate-hide" ng-hide="checked">
20909           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20910         </div>
20911       </div>
20912     </file>
20913     <file name="glyphicons.css">
20914       @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20915     </file>
20916     <file name="animations.css">
20917       .animate-hide {
20918         -webkit-transition:all linear 0.5s;
20919         transition:all linear 0.5s;
20920         line-height:20px;
20921         opacity:1;
20922         padding:10px;
20923         border:1px solid black;
20924         background:white;
20925       }
20926
20927       .animate-hide.ng-hide {
20928         line-height:0;
20929         opacity:0;
20930         padding:0 10px;
20931       }
20932
20933       .check-element {
20934         padding:10px;
20935         border:1px solid black;
20936         background:white;
20937       }
20938     </file>
20939     <file name="protractor.js" type="protractor">
20940       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20941       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20942
20943       it('should check ng-show / ng-hide', function() {
20944         expect(thumbsUp.isDisplayed()).toBeFalsy();
20945         expect(thumbsDown.isDisplayed()).toBeTruthy();
20946
20947         element(by.model('checked')).click();
20948
20949         expect(thumbsUp.isDisplayed()).toBeTruthy();
20950         expect(thumbsDown.isDisplayed()).toBeFalsy();
20951       });
20952     </file>
20953   </example>
20954  */
20955 var ngHideDirective = ['$animate', function($animate) {
20956   return function(scope, element, attr) {
20957     scope.$watch(attr.ngHide, function ngHideWatchAction(value){
20958       $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
20959     });
20960   };
20961 }];
20962
20963 /**
20964  * @ngdoc directive
20965  * @name ngStyle
20966  * @restrict AC
20967  *
20968  * @description
20969  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20970  *
20971  * @element ANY
20972  * @param {expression} ngStyle
20973  *
20974  * {@link guide/expression Expression} which evals to an
20975  * object whose keys are CSS style names and values are corresponding values for those CSS
20976  * keys.
20977  *
20978  * Since some CSS style names are not valid keys for an object, they must be quoted.
20979  * See the 'background-color' style in the example below.
20980  *
20981  * @example
20982    <example>
20983      <file name="index.html">
20984         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
20985         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
20986         <input type="button" value="clear" ng-click="myStyle={}">
20987         <br/>
20988         <span ng-style="myStyle">Sample Text</span>
20989         <pre>myStyle={{myStyle}}</pre>
20990      </file>
20991      <file name="style.css">
20992        span {
20993          color: black;
20994        }
20995      </file>
20996      <file name="protractor.js" type="protractor">
20997        var colorSpan = element(by.css('span'));
20998
20999        it('should check ng-style', function() {
21000          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
21001          element(by.css('input[value=\'set color\']')).click();
21002          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
21003          element(by.css('input[value=clear]')).click();
21004          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
21005        });
21006      </file>
21007    </example>
21008  */
21009 var ngStyleDirective = ngDirective(function(scope, element, attr) {
21010   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
21011     if (oldStyles && (newStyles !== oldStyles)) {
21012       forEach(oldStyles, function(val, style) { element.css(style, '');});
21013     }
21014     if (newStyles) element.css(newStyles);
21015   }, true);
21016 });
21017
21018 /**
21019  * @ngdoc directive
21020  * @name ngSwitch
21021  * @restrict EA
21022  *
21023  * @description
21024  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
21025  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
21026  * as specified in the template.
21027  *
21028  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
21029  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
21030  * matches the value obtained from the evaluated expression. In other words, you define a container element
21031  * (where you place the directive), place an expression on the **`on="..."` attribute**
21032  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
21033  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
21034  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
21035  * attribute is displayed.
21036  *
21037  * <div class="alert alert-info">
21038  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
21039  * as literal string values to match against.
21040  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
21041  * value of the expression `$scope.someVal`.
21042  * </div>
21043
21044  * @animations
21045  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
21046  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
21047  *
21048  * @usage
21049  *
21050  * ```
21051  * <ANY ng-switch="expression">
21052  *   <ANY ng-switch-when="matchValue1">...</ANY>
21053  *   <ANY ng-switch-when="matchValue2">...</ANY>
21054  *   <ANY ng-switch-default>...</ANY>
21055  * </ANY>
21056  * ```
21057  *
21058  *
21059  * @scope
21060  * @priority 800
21061  * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
21062  * On child elements add:
21063  *
21064  * * `ngSwitchWhen`: the case statement to match against. If match then this
21065  *   case will be displayed. If the same match appears multiple times, all the
21066  *   elements will be displayed.
21067  * * `ngSwitchDefault`: the default case when no other case match. If there
21068  *   are multiple default cases, all of them will be displayed when no other
21069  *   case match.
21070  *
21071  *
21072  * @example
21073   <example module="switchExample" deps="angular-animate.js" animations="true">
21074     <file name="index.html">
21075       <div ng-controller="ExampleController">
21076         <select ng-model="selection" ng-options="item for item in items">
21077         </select>
21078         <tt>selection={{selection}}</tt>
21079         <hr/>
21080         <div class="animate-switch-container"
21081           ng-switch on="selection">
21082             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
21083             <div class="animate-switch" ng-switch-when="home">Home Span</div>
21084             <div class="animate-switch" ng-switch-default>default</div>
21085         </div>
21086       </div>
21087     </file>
21088     <file name="script.js">
21089       angular.module('switchExample', ['ngAnimate'])
21090         .controller('ExampleController', ['$scope', function($scope) {
21091           $scope.items = ['settings', 'home', 'other'];
21092           $scope.selection = $scope.items[0];
21093         }]);
21094     </file>
21095     <file name="animations.css">
21096       .animate-switch-container {
21097         position:relative;
21098         background:white;
21099         border:1px solid black;
21100         height:40px;
21101         overflow:hidden;
21102       }
21103
21104       .animate-switch {
21105         padding:10px;
21106       }
21107
21108       .animate-switch.ng-animate {
21109         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21110         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21111
21112         position:absolute;
21113         top:0;
21114         left:0;
21115         right:0;
21116         bottom:0;
21117       }
21118
21119       .animate-switch.ng-leave.ng-leave-active,
21120       .animate-switch.ng-enter {
21121         top:-50px;
21122       }
21123       .animate-switch.ng-leave,
21124       .animate-switch.ng-enter.ng-enter-active {
21125         top:0;
21126       }
21127     </file>
21128     <file name="protractor.js" type="protractor">
21129       var switchElem = element(by.css('[ng-switch]'));
21130       var select = element(by.model('selection'));
21131
21132       it('should start in settings', function() {
21133         expect(switchElem.getText()).toMatch(/Settings Div/);
21134       });
21135       it('should change to home', function() {
21136         select.all(by.css('option')).get(1).click();
21137         expect(switchElem.getText()).toMatch(/Home Span/);
21138       });
21139       it('should select default', function() {
21140         select.all(by.css('option')).get(2).click();
21141         expect(switchElem.getText()).toMatch(/default/);
21142       });
21143     </file>
21144   </example>
21145  */
21146 var ngSwitchDirective = ['$animate', function($animate) {
21147   return {
21148     restrict: 'EA',
21149     require: 'ngSwitch',
21150
21151     // asks for $scope to fool the BC controller module
21152     controller: ['$scope', function ngSwitchController() {
21153      this.cases = {};
21154     }],
21155     link: function(scope, element, attr, ngSwitchController) {
21156       var watchExpr = attr.ngSwitch || attr.on,
21157           selectedTranscludes = [],
21158           selectedElements = [],
21159           previousElements = [],
21160           selectedScopes = [];
21161
21162       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
21163         var i, ii;
21164         for (i = 0, ii = previousElements.length; i < ii; ++i) {
21165           previousElements[i].remove();
21166         }
21167         previousElements.length = 0;
21168
21169         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
21170           var selected = selectedElements[i];
21171           selectedScopes[i].$destroy();
21172           previousElements[i] = selected;
21173           $animate.leave(selected, function() {
21174             previousElements.splice(i, 1);
21175           });
21176         }
21177
21178         selectedElements.length = 0;
21179         selectedScopes.length = 0;
21180
21181         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
21182           scope.$eval(attr.change);
21183           forEach(selectedTranscludes, function(selectedTransclude) {
21184             var selectedScope = scope.$new();
21185             selectedScopes.push(selectedScope);
21186             selectedTransclude.transclude(selectedScope, function(caseElement) {
21187               var anchor = selectedTransclude.element;
21188
21189               selectedElements.push(caseElement);
21190               $animate.enter(caseElement, anchor.parent(), anchor);
21191             });
21192           });
21193         }
21194       });
21195     }
21196   };
21197 }];
21198
21199 var ngSwitchWhenDirective = ngDirective({
21200   transclude: 'element',
21201   priority: 800,
21202   require: '^ngSwitch',
21203   link: function(scope, element, attrs, ctrl, $transclude) {
21204     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
21205     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
21206   }
21207 });
21208
21209 var ngSwitchDefaultDirective = ngDirective({
21210   transclude: 'element',
21211   priority: 800,
21212   require: '^ngSwitch',
21213   link: function(scope, element, attr, ctrl, $transclude) {
21214     ctrl.cases['?'] = (ctrl.cases['?'] || []);
21215     ctrl.cases['?'].push({ transclude: $transclude, element: element });
21216    }
21217 });
21218
21219 /**
21220  * @ngdoc directive
21221  * @name ngTransclude
21222  * @restrict AC
21223  *
21224  * @description
21225  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
21226  *
21227  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
21228  *
21229  * @element ANY
21230  *
21231  * @example
21232    <example module="transcludeExample">
21233      <file name="index.html">
21234        <script>
21235          angular.module('transcludeExample', [])
21236           .directive('pane', function(){
21237              return {
21238                restrict: 'E',
21239                transclude: true,
21240                scope: { title:'@' },
21241                template: '<div style="border: 1px solid black;">' +
21242                            '<div style="background-color: gray">{{title}}</div>' +
21243                            '<div ng-transclude></div>' +
21244                          '</div>'
21245              };
21246          })
21247          .controller('ExampleController', ['$scope', function($scope) {
21248            $scope.title = 'Lorem Ipsum';
21249            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
21250          }]);
21251        </script>
21252        <div ng-controller="ExampleController">
21253          <input ng-model="title"><br>
21254          <textarea ng-model="text"></textarea> <br/>
21255          <pane title="{{title}}">{{text}}</pane>
21256        </div>
21257      </file>
21258      <file name="protractor.js" type="protractor">
21259         it('should have transcluded', function() {
21260           var titleElement = element(by.model('title'));
21261           titleElement.clear();
21262           titleElement.sendKeys('TITLE');
21263           var textElement = element(by.model('text'));
21264           textElement.clear();
21265           textElement.sendKeys('TEXT');
21266           expect(element(by.binding('title')).getText()).toEqual('TITLE');
21267           expect(element(by.binding('text')).getText()).toEqual('TEXT');
21268         });
21269      </file>
21270    </example>
21271  *
21272  */
21273 var ngTranscludeDirective = ngDirective({
21274   link: function($scope, $element, $attrs, controller, $transclude) {
21275     if (!$transclude) {
21276       throw minErr('ngTransclude')('orphan',
21277        'Illegal use of ngTransclude directive in the template! ' +
21278        'No parent directive that requires a transclusion found. ' +
21279        'Element: {0}',
21280        startingTag($element));
21281     }
21282
21283     $transclude(function(clone) {
21284       $element.empty();
21285       $element.append(clone);
21286     });
21287   }
21288 });
21289
21290 /**
21291  * @ngdoc directive
21292  * @name script
21293  * @restrict E
21294  *
21295  * @description
21296  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
21297  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
21298  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
21299  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
21300  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
21301  *
21302  * @param {string} type Must be set to `'text/ng-template'`.
21303  * @param {string} id Cache name of the template.
21304  *
21305  * @example
21306   <example>
21307     <file name="index.html">
21308       <script type="text/ng-template" id="/tpl.html">
21309         Content of the template.
21310       </script>
21311
21312       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
21313       <div id="tpl-content" ng-include src="currentTpl"></div>
21314     </file>
21315     <file name="protractor.js" type="protractor">
21316       it('should load template defined inside script tag', function() {
21317         element(by.css('#tpl-link')).click();
21318         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
21319       });
21320     </file>
21321   </example>
21322  */
21323 var scriptDirective = ['$templateCache', function($templateCache) {
21324   return {
21325     restrict: 'E',
21326     terminal: true,
21327     compile: function(element, attr) {
21328       if (attr.type == 'text/ng-template') {
21329         var templateUrl = attr.id,
21330             // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
21331             text = element[0].text;
21332
21333         $templateCache.put(templateUrl, text);
21334       }
21335     }
21336   };
21337 }];
21338
21339 var ngOptionsMinErr = minErr('ngOptions');
21340 /**
21341  * @ngdoc directive
21342  * @name select
21343  * @restrict E
21344  *
21345  * @description
21346  * HTML `SELECT` element with angular data-binding.
21347  *
21348  * # `ngOptions`
21349  *
21350  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
21351  * elements for the `<select>` element using the array or object obtained by evaluating the
21352  * `ngOptions` comprehension_expression.
21353  *
21354  * When an item in the `<select>` menu is selected, the array element or object property
21355  * represented by the selected option will be bound to the model identified by the `ngModel`
21356  * directive.
21357  *
21358  * <div class="alert alert-warning">
21359  * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
21360  * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
21361  * </div>
21362  *
21363  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
21364  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
21365  * option. See example below for demonstration.
21366  *
21367  * <div class="alert alert-warning">
21368  * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
21369  * of {@link ng.directive:ngRepeat ngRepeat} when you want the
21370  * `select` model to be bound to a non-string value. This is because an option element can only
21371  * be bound to string values at present.
21372  * </div>
21373  *
21374  * @param {string} ngModel Assignable angular expression to data-bind to.
21375  * @param {string=} name Property name of the form under which the control is published.
21376  * @param {string=} required The control is considered valid only if value is entered.
21377  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21378  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21379  *    `required` when you want to data-bind to the `required` attribute.
21380  * @param {comprehension_expression=} ngOptions in one of the following forms:
21381  *
21382  *   * for array data sources:
21383  *     * `label` **`for`** `value` **`in`** `array`
21384  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
21385  *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
21386  *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
21387  *   * for object data sources:
21388  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21389  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21390  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
21391  *     * `select` **`as`** `label` **`group by`** `group`
21392  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
21393  *
21394  * Where:
21395  *
21396  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
21397  *   * `value`: local variable which will refer to each item in the `array` or each property value
21398  *      of `object` during iteration.
21399  *   * `key`: local variable which will refer to a property name in `object` during iteration.
21400  *   * `label`: The result of this expression will be the label for `<option>` element. The
21401  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
21402  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
21403  *      element. If not specified, `select` expression will default to `value`.
21404  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
21405  *      DOM element.
21406  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
21407  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
21408  *     `value` variable (e.g. `value.propertyName`).
21409  *
21410  * @example
21411     <example module="selectExample">
21412       <file name="index.html">
21413         <script>
21414         angular.module('selectExample', [])
21415           .controller('ExampleController', ['$scope', function($scope) {
21416             $scope.colors = [
21417               {name:'black', shade:'dark'},
21418               {name:'white', shade:'light'},
21419               {name:'red', shade:'dark'},
21420               {name:'blue', shade:'dark'},
21421               {name:'yellow', shade:'light'}
21422             ];
21423             $scope.myColor = $scope.colors[2]; // red
21424           }]);
21425         </script>
21426         <div ng-controller="ExampleController">
21427           <ul>
21428             <li ng-repeat="color in colors">
21429               Name: <input ng-model="color.name">
21430               [<a href ng-click="colors.splice($index, 1)">X</a>]
21431             </li>
21432             <li>
21433               [<a href ng-click="colors.push({})">add</a>]
21434             </li>
21435           </ul>
21436           <hr/>
21437           Color (null not allowed):
21438           <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
21439
21440           Color (null allowed):
21441           <span  class="nullable">
21442             <select ng-model="myColor" ng-options="color.name for color in colors">
21443               <option value="">-- choose color --</option>
21444             </select>
21445           </span><br/>
21446
21447           Color grouped by shade:
21448           <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
21449           </select><br/>
21450
21451
21452           Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
21453           <hr/>
21454           Currently selected: {{ {selected_color:myColor}  }}
21455           <div style="border:solid 1px black; height:20px"
21456                ng-style="{'background-color':myColor.name}">
21457           </div>
21458         </div>
21459       </file>
21460       <file name="protractor.js" type="protractor">
21461          it('should check ng-options', function() {
21462            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
21463            element.all(by.model('myColor')).first().click();
21464            element.all(by.css('select[ng-model="myColor"] option')).first().click();
21465            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
21466            element(by.css('.nullable select[ng-model="myColor"]')).click();
21467            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
21468            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
21469          });
21470       </file>
21471     </example>
21472  */
21473
21474 var ngOptionsDirective = valueFn({ terminal: true });
21475 // jshint maxlen: false
21476 var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
21477                          //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
21478   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]+?))?$/,
21479       nullModelCtrl = {$setViewValue: noop};
21480 // jshint maxlen: 100
21481
21482   return {
21483     restrict: 'E',
21484     require: ['select', '?ngModel'],
21485     controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
21486       var self = this,
21487           optionsMap = {},
21488           ngModelCtrl = nullModelCtrl,
21489           nullOption,
21490           unknownOption;
21491
21492
21493       self.databound = $attrs.ngModel;
21494
21495
21496       self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
21497         ngModelCtrl = ngModelCtrl_;
21498         nullOption = nullOption_;
21499         unknownOption = unknownOption_;
21500       };
21501
21502
21503       self.addOption = function(value) {
21504         assertNotHasOwnProperty(value, '"option value"');
21505         optionsMap[value] = true;
21506
21507         if (ngModelCtrl.$viewValue == value) {
21508           $element.val(value);
21509           if (unknownOption.parent()) unknownOption.remove();
21510         }
21511       };
21512
21513
21514       self.removeOption = function(value) {
21515         if (this.hasOption(value)) {
21516           delete optionsMap[value];
21517           if (ngModelCtrl.$viewValue == value) {
21518             this.renderUnknownOption(value);
21519           }
21520         }
21521       };
21522
21523
21524       self.renderUnknownOption = function(val) {
21525         var unknownVal = '? ' + hashKey(val) + ' ?';
21526         unknownOption.val(unknownVal);
21527         $element.prepend(unknownOption);
21528         $element.val(unknownVal);
21529         unknownOption.prop('selected', true); // needed for IE
21530       };
21531
21532
21533       self.hasOption = function(value) {
21534         return optionsMap.hasOwnProperty(value);
21535       };
21536
21537       $scope.$on('$destroy', function() {
21538         // disable unknown option so that we don't do work when the whole select is being destroyed
21539         self.renderUnknownOption = noop;
21540       });
21541     }],
21542
21543     link: function(scope, element, attr, ctrls) {
21544       // if ngModel is not defined, we don't need to do anything
21545       if (!ctrls[1]) return;
21546
21547       var selectCtrl = ctrls[0],
21548           ngModelCtrl = ctrls[1],
21549           multiple = attr.multiple,
21550           optionsExp = attr.ngOptions,
21551           nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21552           emptyOption,
21553           // we can't just jqLite('<option>') since jqLite is not smart enough
21554           // to create it in <select> and IE barfs otherwise.
21555           optionTemplate = jqLite(document.createElement('option')),
21556           optGroupTemplate =jqLite(document.createElement('optgroup')),
21557           unknownOption = optionTemplate.clone();
21558
21559       // find "null" option
21560       for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21561         if (children[i].value === '') {
21562           emptyOption = nullOption = children.eq(i);
21563           break;
21564         }
21565       }
21566
21567       selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21568
21569       // required validator
21570       if (multiple) {
21571         ngModelCtrl.$isEmpty = function(value) {
21572           return !value || value.length === 0;
21573         };
21574       }
21575
21576       if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21577       else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21578       else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21579
21580
21581       ////////////////////////////
21582
21583
21584
21585       function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21586         ngModelCtrl.$render = function() {
21587           var viewValue = ngModelCtrl.$viewValue;
21588
21589           if (selectCtrl.hasOption(viewValue)) {
21590             if (unknownOption.parent()) unknownOption.remove();
21591             selectElement.val(viewValue);
21592             if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21593           } else {
21594             if (isUndefined(viewValue) && emptyOption) {
21595               selectElement.val('');
21596             } else {
21597               selectCtrl.renderUnknownOption(viewValue);
21598             }
21599           }
21600         };
21601
21602         selectElement.on('change', function() {
21603           scope.$apply(function() {
21604             if (unknownOption.parent()) unknownOption.remove();
21605             ngModelCtrl.$setViewValue(selectElement.val());
21606           });
21607         });
21608       }
21609
21610       function setupAsMultiple(scope, selectElement, ctrl) {
21611         var lastView;
21612         ctrl.$render = function() {
21613           var items = new HashMap(ctrl.$viewValue);
21614           forEach(selectElement.find('option'), function(option) {
21615             option.selected = isDefined(items.get(option.value));
21616           });
21617         };
21618
21619         // we have to do it on each watch since ngModel watches reference, but
21620         // we need to work of an array, so we need to see if anything was inserted/removed
21621         scope.$watch(function selectMultipleWatch() {
21622           if (!equals(lastView, ctrl.$viewValue)) {
21623             lastView = shallowCopy(ctrl.$viewValue);
21624             ctrl.$render();
21625           }
21626         });
21627
21628         selectElement.on('change', function() {
21629           scope.$apply(function() {
21630             var array = [];
21631             forEach(selectElement.find('option'), function(option) {
21632               if (option.selected) {
21633                 array.push(option.value);
21634               }
21635             });
21636             ctrl.$setViewValue(array);
21637           });
21638         });
21639       }
21640
21641       function setupAsOptions(scope, selectElement, ctrl) {
21642         var match;
21643
21644         if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21645           throw ngOptionsMinErr('iexp',
21646             "Expected expression in form of " +
21647             "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21648             " but got '{0}'. Element: {1}",
21649             optionsExp, startingTag(selectElement));
21650         }
21651
21652         var displayFn = $parse(match[2] || match[1]),
21653             valueName = match[4] || match[6],
21654             keyName = match[5],
21655             groupByFn = $parse(match[3] || ''),
21656             valueFn = $parse(match[2] ? match[1] : valueName),
21657             valuesFn = $parse(match[7]),
21658             track = match[8],
21659             trackFn = track ? $parse(match[8]) : null,
21660             // This is an array of array of existing option groups in DOM.
21661             // We try to reuse these if possible
21662             // - optionGroupsCache[0] is the options with no option group
21663             // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21664             optionGroupsCache = [[{element: selectElement, label:''}]];
21665
21666         if (nullOption) {
21667           // compile the element since there might be bindings in it
21668           $compile(nullOption)(scope);
21669
21670           // remove the class, which is added automatically because we recompile the element and it
21671           // becomes the compilation root
21672           nullOption.removeClass('ng-scope');
21673
21674           // we need to remove it before calling selectElement.empty() because otherwise IE will
21675           // remove the label from the element. wtf?
21676           nullOption.remove();
21677         }
21678
21679         // clear contents, we'll add what's needed based on the model
21680         selectElement.empty();
21681
21682         selectElement.on('change', function() {
21683           scope.$apply(function() {
21684             var optionGroup,
21685                 collection = valuesFn(scope) || [],
21686                 locals = {},
21687                 key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21688
21689             if (multiple) {
21690               value = [];
21691               for (groupIndex = 0, groupLength = optionGroupsCache.length;
21692                    groupIndex < groupLength;
21693                    groupIndex++) {
21694                 // list of options for that group. (first item has the parent)
21695                 optionGroup = optionGroupsCache[groupIndex];
21696
21697                 for(index = 1, length = optionGroup.length; index < length; index++) {
21698                   if ((optionElement = optionGroup[index].element)[0].selected) {
21699                     key = optionElement.val();
21700                     if (keyName) locals[keyName] = key;
21701                     if (trackFn) {
21702                       for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21703                         locals[valueName] = collection[trackIndex];
21704                         if (trackFn(scope, locals) == key) break;
21705                       }
21706                     } else {
21707                       locals[valueName] = collection[key];
21708                     }
21709                     value.push(valueFn(scope, locals));
21710                   }
21711                 }
21712               }
21713             } else {
21714               key = selectElement.val();
21715               if (key == '?') {
21716                 value = undefined;
21717               } else if (key === ''){
21718                 value = null;
21719               } else {
21720                 if (trackFn) {
21721                   for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21722                     locals[valueName] = collection[trackIndex];
21723                     if (trackFn(scope, locals) == key) {
21724                       value = valueFn(scope, locals);
21725                       break;
21726                     }
21727                   }
21728                 } else {
21729                   locals[valueName] = collection[key];
21730                   if (keyName) locals[keyName] = key;
21731                   value = valueFn(scope, locals);
21732                 }
21733               }
21734             }
21735             ctrl.$setViewValue(value);
21736             render();
21737           });
21738         });
21739
21740         ctrl.$render = render;
21741
21742         scope.$watchCollection(valuesFn, render);
21743         scope.$watchCollection(function () {
21744           var locals = {},
21745               values = valuesFn(scope);
21746           if (values) {
21747             var toDisplay = new Array(values.length);
21748             for (var i = 0, ii = values.length; i < ii; i++) {
21749               locals[valueName] = values[i];
21750               toDisplay[i] = displayFn(scope, locals);
21751             }
21752             return toDisplay;
21753           }
21754         }, render);
21755
21756         if ( multiple ) {
21757           scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
21758         }
21759
21760         function getSelectedSet() {
21761           var selectedSet = false;
21762           if (multiple) {
21763             var modelValue = ctrl.$modelValue;
21764             if (trackFn && isArray(modelValue)) {
21765               selectedSet = new HashMap([]);
21766               var locals = {};
21767               for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21768                 locals[valueName] = modelValue[trackIndex];
21769                 selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21770               }
21771             } else {
21772               selectedSet = new HashMap(modelValue);
21773             }
21774           }
21775           return selectedSet;
21776         }
21777
21778
21779         function render() {
21780               // Temporary location for the option groups before we render them
21781           var optionGroups = {'':[]},
21782               optionGroupNames = [''],
21783               optionGroupName,
21784               optionGroup,
21785               option,
21786               existingParent, existingOptions, existingOption,
21787               modelValue = ctrl.$modelValue,
21788               values = valuesFn(scope) || [],
21789               keys = keyName ? sortedKeys(values) : values,
21790               key,
21791               groupLength, length,
21792               groupIndex, index,
21793               locals = {},
21794               selected,
21795               selectedSet = getSelectedSet(),
21796               lastElement,
21797               element,
21798               label;
21799
21800
21801           // We now build up the list of options we need (we merge later)
21802           for (index = 0; length = keys.length, index < length; index++) {
21803
21804             key = index;
21805             if (keyName) {
21806               key = keys[index];
21807               if ( key.charAt(0) === '$' ) continue;
21808               locals[keyName] = key;
21809             }
21810
21811             locals[valueName] = values[key];
21812
21813             optionGroupName = groupByFn(scope, locals) || '';
21814             if (!(optionGroup = optionGroups[optionGroupName])) {
21815               optionGroup = optionGroups[optionGroupName] = [];
21816               optionGroupNames.push(optionGroupName);
21817             }
21818             if (multiple) {
21819               selected = isDefined(
21820                 selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21821               );
21822             } else {
21823               if (trackFn) {
21824                 var modelCast = {};
21825                 modelCast[valueName] = modelValue;
21826                 selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21827               } else {
21828                 selected = modelValue === valueFn(scope, locals);
21829               }
21830               selectedSet = selectedSet || selected; // see if at least one item is selected
21831             }
21832             label = displayFn(scope, locals); // what will be seen by the user
21833
21834             // doing displayFn(scope, locals) || '' overwrites zero values
21835             label = isDefined(label) ? label : '';
21836             optionGroup.push({
21837               // either the index into array or key from object
21838               id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
21839               label: label,
21840               selected: selected                   // determine if we should be selected
21841             });
21842           }
21843           if (!multiple) {
21844             if (nullOption || modelValue === null) {
21845               // insert null option if we have a placeholder, or the model is null
21846               optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
21847             } else if (!selectedSet) {
21848               // option could not be found, we have to insert the undefined item
21849               optionGroups[''].unshift({id:'?', label:'', selected:true});
21850             }
21851           }
21852
21853           // Now we need to update the list of DOM nodes to match the optionGroups we computed above
21854           for (groupIndex = 0, groupLength = optionGroupNames.length;
21855                groupIndex < groupLength;
21856                groupIndex++) {
21857             // current option group name or '' if no group
21858             optionGroupName = optionGroupNames[groupIndex];
21859
21860             // list of options for that group. (first item has the parent)
21861             optionGroup = optionGroups[optionGroupName];
21862
21863             if (optionGroupsCache.length <= groupIndex) {
21864               // we need to grow the optionGroups
21865               existingParent = {
21866                 element: optGroupTemplate.clone().attr('label', optionGroupName),
21867                 label: optionGroup.label
21868               };
21869               existingOptions = [existingParent];
21870               optionGroupsCache.push(existingOptions);
21871               selectElement.append(existingParent.element);
21872             } else {
21873               existingOptions = optionGroupsCache[groupIndex];
21874               existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
21875
21876               // update the OPTGROUP label if not the same.
21877               if (existingParent.label != optionGroupName) {
21878                 existingParent.element.attr('label', existingParent.label = optionGroupName);
21879               }
21880             }
21881
21882             lastElement = null;  // start at the beginning
21883             for(index = 0, length = optionGroup.length; index < length; index++) {
21884               option = optionGroup[index];
21885               if ((existingOption = existingOptions[index+1])) {
21886                 // reuse elements
21887                 lastElement = existingOption.element;
21888                 if (existingOption.label !== option.label) {
21889                   lastElement.text(existingOption.label = option.label);
21890                 }
21891                 if (existingOption.id !== option.id) {
21892                   lastElement.val(existingOption.id = option.id);
21893                 }
21894                 // lastElement.prop('selected') provided by jQuery has side-effects
21895                 if (lastElement[0].selected !== option.selected) {
21896                   lastElement.prop('selected', (existingOption.selected = option.selected));
21897                   if (msie) {
21898                     // See #7692
21899                     // The selected item wouldn't visually update on IE without this.
21900                     // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
21901                     lastElement.prop('selected', existingOption.selected);
21902                   }
21903                 }
21904               } else {
21905                 // grow elements
21906
21907                 // if it's a null option
21908                 if (option.id === '' && nullOption) {
21909                   // put back the pre-compiled element
21910                   element = nullOption;
21911                 } else {
21912                   // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
21913                   // in this version of jQuery on some browser the .text() returns a string
21914                   // rather then the element.
21915                   (element = optionTemplate.clone())
21916                       .val(option.id)
21917                       .prop('selected', option.selected)
21918                       .attr('selected', option.selected)
21919                       .text(option.label);
21920                 }
21921
21922                 existingOptions.push(existingOption = {
21923                     element: element,
21924                     label: option.label,
21925                     id: option.id,
21926                     selected: option.selected
21927                 });
21928                 if (lastElement) {
21929                   lastElement.after(element);
21930                 } else {
21931                   existingParent.element.append(element);
21932                 }
21933                 lastElement = element;
21934               }
21935             }
21936             // remove any excessive OPTIONs in a group
21937             index++; // increment since the existingOptions[0] is parent element not OPTION
21938             while(existingOptions.length > index) {
21939               existingOptions.pop().element.remove();
21940             }
21941           }
21942           // remove any excessive OPTGROUPs from select
21943           while(optionGroupsCache.length > groupIndex) {
21944             optionGroupsCache.pop()[0].element.remove();
21945           }
21946         }
21947       }
21948     }
21949   };
21950 }];
21951
21952 var optionDirective = ['$interpolate', function($interpolate) {
21953   var nullSelectCtrl = {
21954     addOption: noop,
21955     removeOption: noop
21956   };
21957
21958   return {
21959     restrict: 'E',
21960     priority: 100,
21961     compile: function(element, attr) {
21962       if (isUndefined(attr.value)) {
21963         var interpolateFn = $interpolate(element.text(), true);
21964         if (!interpolateFn) {
21965           attr.$set('value', element.text());
21966         }
21967       }
21968
21969       return function (scope, element, attr) {
21970         var selectCtrlName = '$selectController',
21971             parent = element.parent(),
21972             selectCtrl = parent.data(selectCtrlName) ||
21973               parent.parent().data(selectCtrlName); // in case we are in optgroup
21974
21975         if (selectCtrl && selectCtrl.databound) {
21976           // For some reason Opera defaults to true and if not overridden this messes up the repeater.
21977           // We don't want the view to drive the initialization of the model anyway.
21978           element.prop('selected', false);
21979         } else {
21980           selectCtrl = nullSelectCtrl;
21981         }
21982
21983         if (interpolateFn) {
21984           scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
21985             attr.$set('value', newVal);
21986             if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
21987             selectCtrl.addOption(newVal);
21988           });
21989         } else {
21990           selectCtrl.addOption(attr.value);
21991         }
21992
21993         element.on('$destroy', function() {
21994           selectCtrl.removeOption(attr.value);
21995         });
21996       };
21997     }
21998   };
21999 }];
22000
22001 var styleDirective = valueFn({
22002   restrict: 'E',
22003   terminal: true
22004 });
22005
22006   if (window.angular.bootstrap) {
22007     //AngularJS is already loaded, so we can return here...
22008     console.log('WARNING: Tried to load angular more than once.');
22009     return;
22010   }
22011
22012   //try to bind to jquery now so that one can write angular.element().read()
22013   //but we will rebind on bootstrap again.
22014   bindJQuery();
22015
22016   publishExternalAPI(angular);
22017
22018   jqLite(document).ready(function() {
22019     angularInit(document, bootstrap);
22020   });
22021
22022 })(window, document);
22023
22024 !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{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}.ng-hide-add-active,.ng-hide-remove{display:block!important;}</style>');