PageSourceSearch

https://cryptobarons.io/Content/CryptoBarons/apps/angular/dist/angularjs/angular.js?appVersionDynamic=1.2.3

js cryptobarons.io collected 2026-10-04 20:24:26 UTC 791,753 bytes, 21,778 lines download raw bytes

1/**
2 * @license AngularJS v1.2.19
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
36function 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.19/' +
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
84    -angular,
85    -msie,
86    -jqLite,
87    -jQuery,
88    -slice,
89    -push,
90    -toString,
91    -ngMinErr,
92    -angularModule,
93    -nodeName_,
94    -uid,
95    -VALIDITY_STATE_PROPERTY,
96
97    -lowercase,
98    -uppercase,
99    -manualLowercase,
100    -manualUppercase,
101    -nodeName_,
102    -isArrayLike,
103    -forEach,
104    -sortedKeys,
105    -forEachSorted,
106    -reverseParams,
107    -nextUid,
108    -setHashKey,
109    -extend,
110    -int,
111    -inherit,
112    -noop,
113    -identity,
114    -valueFn,
115    -isUndefined,
116    -isDefined,
117    -isObject,
118    -isString,
119    -isNumber,
120    -isDate,
121    -isArray,
122    -isFunction,
123    -isRegExp,
124    -isWindow,
125    -isScope,
126    -isFile,
127    -isBlob,
128    -isBoolean,
129    -trim,
130    -isElement,
131    -makeMap,
132    -map,
133    -size,
134    -includes,
135    -indexOf,
136    -arrayRemove,
137    -isLeafNode,
138    -copy,
139    -shallowCopy,
140    -equals,
141    -csp,
142    -concat,
143    -sliceArgs,
144    -bind,
145    -toJsonReplacer,
146    -toJson,
147    -fromJson,
148    -toBoolean,
149    -startingTag,
150    -tryDecodeURIComponent,
151    -parseKeyValue,
152    -toKeyValue,
153    -encodeUriSegment,
154    -encodeUriQuery,
155    -angularInit,
156    -bootstrap,
157    -snake_case,
158    -bindJQuery,
159    -assertArg,
160    -assertArgFn,
161    -assertNotHasOwnProperty,
162    -getter,
163    -getBlockElements,
164    -hasOwnProperty,
165
166*/
167
168////////////////////////////////////
169
170/**
171 * @ngdoc module
172 * @name ng
173 * @module ng
174 * @description
175 *
176 * # ng (core module)
177 * The ng module is loaded by default when an AngularJS application is started. The module itself
178 * contains the essential components for an AngularJS application to function. The table below
179 * lists a high level breakdown of each of the services/factories, filters, directives and testing
180 * components available within this core module.
181 *
182 * <div doc-module-components="ng"></div>
183 */
184
185// The name of a form control's ValidityState property.
186// This is used so that it's possible for internal tests to create mock ValidityStates.
187var VALIDITY_STATE_PROPERTY = 'validity';
188
189/**
190 * @ngdoc function
191 * @name angular.lowercase
192 * @module ng
193 * @kind function
194 *
195 * @description Converts the specified string to lowercase.
196 * @param {string} string String to be converted to lowercase.
197 * @returns {string} Lowercased string.
198 */
199var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
200var hasOwnProperty = Object.prototype.hasOwnProperty;
201
202/**
203 * @ngdoc function
204 * @name angular.uppercase
205 * @module ng
206 * @kind function
207 *
208 * @description Converts the specified string to uppercase.
209 * @param {string} string String to be converted to uppercase.
210 * @returns {string} Uppercased string.
211 */
212var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
213
214
215var manualLowercase = function(s) {
216  /* jshint bitwise: false */
217  return isString(s)
218      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
219      : s;
220};
221var manualUppercase = function(s) {
222  /* jshint bitwise: false */
223  return isString(s)
224      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
225      : s;
226};
227
228
229// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
230// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
231// with correct but slower alternatives.
232if ('i' !== 'I'.toLowerCase()) {
233  lowercase = manualLowercase;
234  uppercase = manualUppercase;
235}
236
237
238var /** holds major version number for IE or NaN for real browsers */
239    msie,
240    jqLite,           // delay binding since jQuery could be loaded after us.
241    jQuery,           // delay binding
242    slice             = [].slice,
243    push              = [].push,
244    toString          = Object.prototype.toString,
245    ngMinErr          = minErr('ng'),
246
247    /** @name angular */
248    angular           = window.angular || (window.angular = {}),
249    angularModule,
250    nodeName_,
251    uid               = ['0', '0', '0'];
252
253/**
254 * IE 11 changed the format of the UserAgent string.
255 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
256 */
257msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
258if (isNaN(msie)) {
259  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
260}
261
262
263/**
264 * @private
265 * @param {*} obj
266 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
267 *                   String ...)
268 */
269function isArrayLike(obj) {
270  if (obj == null || isWindow(obj)) {
271    return false;
272  }
273
274  var length = obj.length;
275
276  if (obj.nodeType === 1 && length) {
277    return true;
278  }
279
280  return isString(obj) || isArray(obj) || length === 0 ||
281         typeof length === 'number' && length > 0 && (length - 1) in obj;
282}
283
284/**
285 * @ngdoc function
286 * @name angular.forEach
287 * @module ng
288 * @kind function
289 *
290 * @description
291 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
292 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
293 * is the value of an object property or an array element and `key` is the object property key or
294 * array element index. Specifying a `context` for the function is optional.
295 *
296 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
297 * using the `hasOwnProperty` method.
298 *
299   ```js
300     var values = {name: 'misko', gender: 'male'};
301     var log = [];
302     angular.forEach(values, function(value, key) {
303       this.push(key + ': ' + value);
304     }, log);
305     expect(log).toEqual(['name: misko', 'gender: male']);
306   ```
307 *
308 * @param {Object|Array} obj Object to iterate over.
309 * @param {Function} iterator Iterator function.
310 * @param {Object=} context Object to become context (`this`) for the iterator function.
311 * @returns {Object|Array} Reference to `obj`.
312 */
313function forEach(obj, iterator, context) {
314  var key;
315  if (obj) {
316    if (isFunction(obj)) {
317      for (key in obj) {
318        // Need to check if hasOwnProperty exists,
319        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
320        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
321          iterator.call(context, obj[key], key);
322        }
323      }
324    }
324 else if (obj.forEach && obj.forEach !== forEach) {
325      obj.forEach(iterator, context);
326    } else if (isArrayLike(obj)) {
327      for (key = 0; key < obj.length; key++)
328        iterator.call(context, obj[key], key);
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
340function 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
350function 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 */
364function 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 */
376function 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 */
404function 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 */
427function 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
441function int(str) {
442  return parseInt(str, 10);
443}
444
445
446function 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 */
466function noop() {}
467noop.$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 */
486function identity($) {return $;}
487identity.$inject = [];
488
489
490function 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 */
504function 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 */
519function 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 */
535function 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 */
550function 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 */
565function 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 */
580function 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 */
597var 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 */
618function 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 */
628function 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 */
640function isWindow(obj) {
641  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
642}
643
644
645function isScope(obj) {
646  return obj && obj.$evalAsync && obj.$watch;
647}
648
649
650function isFile(obj) {
651  return toString.call(obj) === '[object File]';
652}
653
654
655function isBlob(obj) {
656  return toString.call(obj) === '[object Blob]';
657}
658
659
660function isBoolean(value) {
661  return typeof value === 'boolean';
662}
663
664
665var trim = (function() {
666  // native trim is way faster: http://jsperf.com/angular-trim-test
667  // but IE doesn't have it... :-(
668  // TODO: we should move this into IE/ES5 polyfill
669  if (!String.prototype.trim) {
670    return function(value) {
671      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
672    };
673  }
674  return function(value) {
675    return isString(value) ? value.trim() : value;
676  };
677})();
678
679
680/**
681 * @ngdoc function
682 * @name angular.isElement
683 * @module ng
684 * @kind function
685 *
686 * @description
687 * Determines if a reference is a DOM element (or wrapped jQuery element).
688 *
689 * @param {*} value Reference to check.
690 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
691 */
692function isElement(node) {
693  return !!(node &&
694    (node.nodeName  // we are a direct element
695    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
696}
697
698/**
699 * @param str 'key1,key2,...'
700 * @returns {object} in the form of {key1:true, key2:true, ...}
701 */
702function makeMap(str) {
703  var obj = {}, items = str.split(","), i;
704  for ( i = 0; i < items.length; i++ )
705    obj[ items[i] ] = true;
706  return obj;
707}
708
709
710if (msie < 9) {
711  nodeName_ = function(element) {
712    element = element.nodeName ? element : element[0];
713    return (element.scopeName && element.scopeName != 'HTML')
714      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
715  };
716} else {
717  nodeName_ = function(element) {
718    return element.nodeName ? element.nodeName : element[0].nodeName;
719  };
720}
721
722
723function map(obj, iterator, context) {
724  var results = [];
725  forEach(obj, function(value, index, list) {
726    results.push(iterator.call(context, value, index, list));
727  });
728  return results;
729}
730
731
732/**
733 * @description
734 * Determines the number of elements in an array, the number of properties an object has, or
735 * the length of a string.
736 *
737 * Note: This function is used to augment the Object type in Angular expressions. See
738 * {@link angular.Object} for more information about Angular arrays.
739 *
740 * @param {Object|Array|string} obj Object, array, or string to inspect.
741 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
742 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
743 */
744function size(obj, ownPropsOnly) {
745  var count = 0, key;
746
747  if (isArray(obj) || isString(obj)) {
748    return obj.length;
749  } else if (isObject(obj)) {
750    for (key in obj)
751      if (!ownPropsOnly || obj.hasOwnProperty(key))
752        count++;
753  }
754
755  return count;
756}
757
758
759function includes(array, obj) {
760  return indexOf(array, obj) != -1;
761}
762
763function indexOf(array, obj) {
764  if (array.indexOf) return array.indexOf(obj);
765
766  for (var i = 0; i < array.length; i++) {
767    if (obj === array[i]) return i;
768  }
769  return -1;
770}
771
772function arrayRemove(array, value) {
773  var index = indexOf(array, value);
774  if (index >=0)
775    array.splice(index, 1);
776  return value;
777}
778
779function isLeafNode (node) {
780  if (node) {
781    switch (node.nodeName) {
782    case "OPTION":
783    case "PRE":
784    case "TITLE":
785      return true;
786    }
787  }
788  return false;
789}
790
791/**
792 * @ngdoc function
793 * @name angular.copy
794 * @module ng
795 * @kind function
796 *
797 * @description
798 * Creates a deep copy of `source`, which should be an object or an array.
799 *
800 * * If no destination is supplied, a copy of the object or array is created.
801 * * If a destination is provided, all of its elements (for array) or properties (for objects)
802 *   are deleted and then all elements/properties from the source are copied to it.
803 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
804 * * If `source` is identical to 'destination' an exception will be thrown.
805 *
806 * @param {*} source The source that will be used to make a copy.
807 *                   Can be any type, including primitives, `null`, and `undefined`.
808 * @param {(Object|Array)=} destination Destination into which the source is copied. If
809 *     provided, must be of the same type as `source`.
810 * @returns {*} The copy or updated `destination`, if `destination` was specified.
811 *
812 * @example
813 <example>
814 <file name="index.html">
815 <div ng-controller="Controller">
816 <form novalidate class="simple-form">
817 Name: <input type="text" ng-model="user.name" /><br />
818 E-mail: <input type="email" ng-model="user.email" /><br />
819 Gender: <input type="radio" ng-model="user.gender" value="male" />male
820 <input type="radio" ng-model="user.gender" value="female" />female<br />
821 <button ng-click="reset()">RESET</button>
822 <button ng-click="update(user)">SAVE</button>
823 </form>
824 <pre>form = {{user | json}}</pre>
825 <pre>master = {{master | json}}</pre>
826 </div>
827
828 <script>
829 function Controller($scope) {
830    $scope.master= {};
831
832    $scope.update = function(user) {
833      // Example with 1 argument
834      $scope.master= angular.copy(user);
835    };
836
837    $scope.reset = function() {
838      // Example with 2 arguments
839      angular.copy($scope.master, $scope.user);
840    };
841
842    $scope.reset();
843  }
844 </script>
845 </file>
846 </example>
847 */
848function copy(source, destination, stackSource, stackDest) {
849  if (isWindow(source) || isScope(source)) {
850    throw ngMinErr('cpws',
851      "Can't copy! Making copies of Window or Scope instances is not supported.");
852  }
853
854  if (!destination) {
855    destination = source;
856    if (source) {
857      if (isArray(source)) {
858        destination = copy(source, [], stackSource, stackDest);
859      } else if (isDate(source)) {
860        destination = new Date(source.getTime());
861      } else if (isRegExp(source)) {
862        destination = new RegExp(source.source);
863      } else if (isObject(source)) {
864        destination = copy(source, {}, stackSource, stackDest);
865      }
866    }
867  } else {
868    if (source === destination) throw ngMinErr('cpi',
869      "Can't copy! Source and destination are identical.");
870
871    stackSource = stackSource || [];
872    stackDest = stackDest || [];
873
874    if (isObject(source)) {
875      var index = indexOf(stackSource, source);
876      if (index !== -1) return stackDest[index];
877
878      stackSource.push(source);
879      stackDest.push(destination);
880    }
881
882    var result;
883    if (isArray(source)) {
884      destination.length = 0;
885      for ( var i = 0; i < source.length; i++) {
886        result = copy(source[i], null, stackSource, stackDest);
887        if (isObject(source[i])) {
888          stackSource.push(source[i]);
889          stackDest.push(result);
890        }
891        destination.push(result);
892      }
893    } else {
894      var h = destination.$$hashKey;
895      forEach(destination, function(value, key) {
896        delete destination[key];
897      });
898      for ( var key in source) {
899        result = copy(source[key], null, stackSource, stackDest);
900        if (isObject(source[key])) {
901          stackSource.push(source[key]);
902          stackDest.push(result);
903        }
904        destination[key] = result;
905      }
906      setHashKey(destination,h);
907    }
908
909  }
910  return destination;
911}
912
913/**
914 * Creates a shallow copy of an object, an array or a primitive
915 */
916function shallowCopy(src, dst) {
917  if (isArray(src)) {
918    dst = dst || [];
919
920    for ( var i = 0; i < src.length; i++) {
921      dst[i] = src[i];
922    }
923  } else if (isObject(src)) {
924    dst = dst || {};
925
926    for (var key in src) {
927      if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
928        dst[key] = src[key];
929      }
930    }
931  }
932
933  return dst || src;
934}
935
936
937/**
938 * @ngdoc function
939 * @name angular.equals
940 * @module ng
941 * @kind function
942 *
943 * @description
944 * Determines if two objects or two values are equivalent. Supports value types, regular
945 * expressions, arrays and objects.
946 *
947 * Two objects or values are considered equivalent if at least one of the following is true:
948 *
949 * * Both objects or values pass `===` comparison.
950 * * Both objects or values are of the same type and all of their properties are equal by
951 *   comparing them with `angular.equals`.
952 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
953 * * Both values represent the same regular expression (In JavaScript,
954 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
955 *   representation matches).
956 *
957 * During a property comparison, properties of `function` type and properties with names
958 * that begin with `$` are ignored.
959 *
960 * Scope and DOMWindow objects are being compared only by identify (`===`).
961 *
962 * @param {*} o1 Object or value to compare.
963 * @param {*} o2 Object or value to compare.
964 * @returns {boolean} True if arguments are equal.
965 */
966function equals(o1, o2) {
967  if (o1 === o2) return true;
968  if (o1 === null || o2 === null) return false;
969  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
970  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
971  if (t1 == t2) {
972    if (t1 == 'object') {
973      if (isArray(o1)) {
974        if (!isArray(o2)) return false;
975        if ((length = o1.length) == o2.length) {
976          for(key=0; key<length; key++) {
977            if (!equals(o1[key], o2[key])) return false;
978          }
979          return true;
980        }
981      } else if (isDate(o1)) {
982        return isDate(o2) && o1.getTime() == o2.getTime();
983      } else if (isRegExp(o1) && isRegExp(o2)) {
984        return o1.toString() == o2.toString();
985      } else {
986        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
987        keySet = {};
988        for(key in o1) {
989          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
990          if (!equals(o1[key], o2[key])) return false;
991          keySet[key] = true;
992        }
993        for(key in o2) {
994          if (!keySet.hasOwnProperty(key) &&
995              key.charAt(0) !== '$' &&
996              o2[key] !== undefined &&
997              !isFunction(o2[key])) return false;
998        }
999        return true;
1000      }
1001    }
1002  }
1003  return false;
1004}
1005
1006
1007function csp() {
1008  return (document.securityPolicy && document.securityPolicy.isActive) ||
1009      (document.querySelector &&
1010      !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
1011}
1012
1013
1014function concat(array1, array2, index) {
1015  return array1.concat(slice.call(array2, index));
1016}
1017
1018function sliceArgs(args, startIndex) {
1019  return slice.call(args, startIndex || 0);
1020}
1021
1022
1023/* jshint -W101 */
1024/**
1025 * @ngdoc function
1026 * @name angular.bind
1027 * @module ng
1028 * @kind function
1029 *
1030 * @description
1031 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1032 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1033 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1034 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1035 *
1036 * @param {Object} self Context which `fn` should be evaluated in.
1037 * @param {function()} fn Function to be bound.
1038 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1039 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1040 */
1041/* jshint +W101 */
1042function bind(self, fn) {
1043  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1044  if (isFunction(fn) && !(fn instanceof RegExp)) {
1045    return curryArgs.length
1046      ? function() {
1047          return arguments.length
1048            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1049            : fn.apply(self, curryArgs);
1050        }
1051      : function() {
1052          return arguments.length
1053            ? fn.apply(self, arguments)
1054            : fn.call(self);
1055        };
1056  } else {
1057    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1058    return fn;
1059  }
1060}
1061
1062
1063function toJsonReplacer(key, value) {
1064  var val = value;
1065
1066  if (typeof key === 'string' && key.charAt(0) === '$') {
1067    val = undefined;
1068  } else if (isWindow(value)) {
1069    val = '$WINDOW';
1070  } else if (value &&  document === value) {
1071    val = '$DOCUMENT';
1072  } else if (isScope(value)) {
1073    val = '$SCOPE';
1074  }
1075
1076  return val;
1077}
1078
1079
1080/**
1081 * @ngdoc function
1082 * @name angular.toJson
1083 * @module ng
1084 * @kind function
1085 *
1086 * @description
1087 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1088 * stripped since angular uses this notation internally.
1089 *
1090 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1091 * @param {boolean=}
1091 pretty If set to true, the JSON output will contain newlines and whitespace.
1092 * @returns {string|undefined} JSON-ified string representing `obj`.
1093 */
1094function toJson(obj, pretty) {
1095  if (typeof obj === 'undefined') return undefined;
1096  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1097}
1098
1099
1100/**
1101 * @ngdoc function
1102 * @name angular.fromJson
1103 * @module ng
1104 * @kind function
1105 *
1106 * @description
1107 * Deserializes a JSON string.
1108 *
1109 * @param {string} json JSON string to deserialize.
1110 * @returns {Object|Array|string|number} Deserialized thingy.
1111 */
1112function fromJson(json) {
1113  return isString(json)
1114      ? JSON.parse(json)
1115      : json;
1116}
1117
1118
1119function toBoolean(value) {
1120  if (typeof value === 'function') {
1121    value = true;
1122  } else if (value && value.length !== 0) {
1123    var v = lowercase("" + value);
1124    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1125  } else {
1126    value = false;
1127  }
1128  return value;
1129}
1130
1131/**
1132 * @returns {string} Returns the string representation of the element.
1133 */
1134function startingTag(element) {
1135  element = jqLite(element).clone();
1136  try {
1137    // turns out IE does not let you set .html() on elements which
1138    // are not allowed to have children. So we just ignore it.
1139    element.empty();
1140  } catch(e) {}
1141  // As Per DOM Standards
1142  var TEXT_NODE = 3;
1143  var elemHtml = jqLite('<div>').append(element).html();
1144  try {
1145    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1146        elemHtml.
1147          match(/^(<[^>]+>)/)[1].
1148          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1149  } catch(e) {
1150    return lowercase(elemHtml);
1151  }
1152
1153}
1154
1155
1156/////////////////////////////////////////////////
1157
1158/**
1159 * Tries to decode the URI component without throwing an exception.
1160 *
1161 * @private
1162 * @param str value potential URI component to check.
1163 * @returns {boolean} True if `value` can be decoded
1164 * with the decodeURIComponent function.
1165 */
1166function tryDecodeURIComponent(value) {
1167  try {
1168    return decodeURIComponent(value);
1169  } catch(e) {
1170    // Ignore any invalid uri component
1171  }
1172}
1173
1174
1175/**
1176 * Parses an escaped url query string into key-value pairs.
1177 * @returns {Object.<string,boolean|Array>}
1178 */
1179function parseKeyValue(/**string*/keyValue) {
1180  var obj = {}, key_value, key;
1181  forEach((keyValue || "").split('&'), function(keyValue) {
1182    if ( keyValue ) {
1183      key_value = keyValue.split('=');
1184      key = tryDecodeURIComponent(key_value[0]);
1185      if ( isDefined(key) ) {
1186        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1187        if (!obj[key]) {
1188          obj[key] = val;
1189        } else if(isArray(obj[key])) {
1190          obj[key].push(val);
1191        } else {
1192          obj[key] = [obj[key],val];
1193        }
1194      }
1195    }
1196  });
1197  return obj;
1198}
1199
1200function toKeyValue(obj) {
1201  var parts = [];
1202  forEach(obj, function(value, key) {
1203    if (isArray(value)) {
1204      forEach(value, function(arrayValue) {
1205        parts.push(encodeUriQuery(key, true) +
1206                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1207      });
1208    } else {
1209    parts.push(encodeUriQuery(key, true) +
1210               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1211    }
1212  });
1213  return parts.length ? parts.join('&') : '';
1214}
1215
1216
1217/**
1218 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1219 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1220 * segments:
1221 *    segment       = *pchar
1222 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1223 *    pct-encoded   = "%" HEXDIG HEXDIG
1224 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1225 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1226 *                     / "*" / "+" / "," / ";" / "="
1227 */
1228function encodeUriSegment(val) {
1229  return encodeUriQuery(val, true).
1230             replace(/%26/gi, '&').
1231             replace(/%3D/gi, '=').
1232             replace(/%2B/gi, '+');
1233}
1234
1235
1236/**
1237 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1238 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1239 * encoded per http://tools.ietf.org/html/rfc3986:
1240 *    query       = *( pchar / "/" / "?" )
1241 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1242 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1243 *    pct-encoded   = "%" HEXDIG HEXDIG
1244 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1245 *                     / "*" / "+" / "," / ";" / "="
1246 */
1247function encodeUriQuery(val, pctEncodeSpaces) {
1248  return encodeURIComponent(val).
1249             replace(/%40/gi, '@').
1250             replace(/%3A/gi, ':').
1251             replace(/%24/g, '$').
1252             replace(/%2C/gi, ',').
1253             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1254}
1255
1256
1257/**
1258 * @ngdoc directive
1259 * @name ngApp
1260 * @module ng
1261 *
1262 * @element ANY
1263 * @param {angular.Module} ngApp an optional application
1264 *   {@link angular.module module} name to load.
1265 *
1266 * @description
1267 *
1268 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1269 * designates the **root element** of the application and is typically placed near the root element
1270 * of the page - e.g. on the `<body>` or `<html>` tags.
1271 *
1272 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
1272p`
1273 * found in the document will be used to define the root element to auto-bootstrap as an
1274 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1275 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1276 *
1277 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1278 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1279 * should contain the application code needed or have dependencies on other modules that will
1280 * contain the code. See {@link angular.module} for more information.
1281 *
1282 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1283 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1284 * would not be resolved to `3`.
1285 *
1286 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1287 *
1288 <example module="ngAppDemo">
1289   <file name="index.html">
1290   <div ng-controller="ngAppDemoController">
1291     I can add: {{a}} + {{b}} =  {{ a+b }}
1292   </div>
1293   </file>
1294   <file name="script.js">
1295   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1296     $scope.a = 1;
1297     $scope.b = 2;
1298   });
1299   </file>
1300 </example>
1301 *
1302 */
1303function angularInit(element, bootstrap) {
1304  var elements = [element],
1305      appElement,
1306      module,
1307      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1308      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1309
1310  function append(element) {
1311    element && elements.push(element);
1312  }
1313
1314  forEach(names, function(name) {
1315    names[name] = true;
1316    append(document.getElementById(name));
1317    name = name.replace(':', '\\:');
1318    if (element.querySelectorAll) {
1319      forEach(element.querySelectorAll('.' + name), append);
1320      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1321      forEach(element.querySelectorAll('[' + name + ']'), append);
1322    }
1323  });
1324
1325  forEach(elements, function(element) {
1326    if (!appElement) {
1327      var className = ' ' + element.className + ' ';
1328      var match = NG_APP_CLASS_REGEXP.exec(className);
1329      if (match) {
1330        appElement = element;
1331        module = (match[2] || '').replace(/\s+/g, ',');
1332      } else {
1333        forEach(element.attributes, function(attr) {
1334          if (!appElement && names[attr.name]) {
1335            appElement = element;
1336            module = attr.value;
1337          }
1338        });
1339      }
1340    }
1341  });
1342  if (appElement) {
1343    bootstrap(appElement, module ? [module] : []);
1344  }
1345}
1346
1347/**
1348 * @ngdoc function
1349 * @name angular.bootstrap
1350 * @module ng
1351 * @description
1352 * Use this function to manually start up angular application.
1353 *
1354 * See: {@link guide/bootstrap Bootstrap}
1355 *
1356 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1357 * They must use {@link ng.directive:ngApp ngApp}.
1358 *
1359 * Angular will detect if it has been loaded into the browser more than once and only allow the
1360 * first loaded script to be bootstrapped and will report a warning to the browser console for
1361 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1362 * multiple instances of Angular try to work on the DOM.
1363 *
1364 * <example name="multi-bootstrap" module="multi-bootstrap">
1365 * <file name="index.html">
1366 * <script src="../../../angular.js"></script>
1367 * <div ng-controller="BrokenTable">
1368 *   <table>
1369 *   <tr>
1370 *     <th ng-repeat="heading in headings">{{heading}}</th>
1371 *   </tr>
1372 *   <tr ng-repeat="filling in fillings">
1373 *     <td ng-repeat="fill in filling">{{fill}}</td>
1374 *   </tr>
1375 * </table>
1376 * </div>
1377 * </file>
1378 * <file name="controller.js">
1379 * var app = angular.module('multi-bootstrap', [])
1380 *
1381 * .controller('BrokenTable', function($scope) {
1382 *     $scope.headings = ['One', 'Two', 'Three'];
1383 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1384 * });
1385 * </file>
1386 * <file name="protractor.js" type="protractor">
1387 * it('should only insert one table cell for each item in $scope.fillings', function() {
1388 *  expect(element.all(by.css('td')).count())
1389 *      .toBe(9);
1390 * });
1391 * </file>
1392 * </example>
1393 *
1394 * @param {DOMElement} element DOM element which is the root of angular application.
1395 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1396 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1397 *     function that will be invoked by the injector as a run block.
1398 *     See: {@link angular.module modules}
1399 * @returns {auto.$injector} Returns the newly created injector for this app.
1400 */
1401function bootstrap(element, modules) {
1402  var doBootstrap = function() {
1403    element = jqLite(element);
1404
1405    if (element.injector()) {
1406      var tag = (element[0] === document) ? 'document' : startingTag(element);
1407      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1408    }
1409
1410    modules = modules || [];
1411    modules.unshift(['$provide', function($provide) {
1412      $provide.value('$rootElement', element);
1413    }]);
1414    modules.unshift('ng');
1415    var injector = createInjector(modules);
1416    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1417       function(scope, element, compile, injector, animate) {
1418        scope.$apply(function() {
1419          element.data('$injector', injector);
1420          compile(element)(scope);
1421        });
1422      }]
1423    );
1424    return injector;
1425  };
1426
1427  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1428
1429  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1430    return doBootstrap();
1431  }
1432
1433  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1434  angular.resumeBootstrap = function(extraModules) {
1435    forEach(extraModules, function(module) {
1436      modules.push(module);
1437    });
1438    doBootstrap();
1439  };
1440}
1441
1442var SNAKE_CASE_REGEXP = /[A-Z]/g;
1443function snake_case(name, separator) {
1444  separator = separator || '_';
1445  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1446    return (pos ? separator : '') + letter.toLowerCase();
1447  });
1448}
1449
1450function bindJQuery() {
1451  // bind to jQuery if present;
1452  jQuery = window.jQuery;
1453  // Use jQuery if it exists with proper functionality, otherwise default to us.
1454  // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
1455  if (jQuery && jQuery.fn.on) {
1456    jqLite = jQuery;
1457    extend(jQuery.fn, {
1458      scope: JQLitePrototype.scope,
1459      isolateScope: JQLitePrototype.isolateScope,
1460      controller: JQLitePrototype.controller,
1461      injector: JQLitePrototype.injector,
1462      inheritedData: JQLitePrototype.inheritedData
1463    });
1464    // Method signature:
1465    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1466    jqLitePatchJQueryRemove('remove', true, true, false);
1467    jqLitePatchJQueryRemove('empty', false, false, false);
1468    jqLitePatchJQueryRemove('html', false, false, true);
1469  } else {
1470    jqLite = JQLite;
1471  }
1472  angular.element = jqLite;
1473}
1474
1475/**
1476 * throw error if the argument is falsy.
1477 */
1478function assertArg(arg, name, reason) {
1479  if (!arg) {
1480    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1481  }
1482  return arg;
1483}
1484
1485function assertArgFn(arg, name, acceptArrayAnnotation) {
1486  if (acceptArrayAnnotation && isArray(arg)) {
1487      arg = arg[arg.length - 1];
1488  }
1489
1490  assertArg(isFunction(arg), name, 'not a function, got ' +
1491      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1492  return arg;
1493}
1494
1495/**
1496 * throw error if the name given is hasOwnProperty
1497 * @param  {String} name    the name to test
1498 * @param  {String} context the context in which the name is used, such as module or directive
1499 */
1500function assertNotHasOwnProperty(name, context) {
1501  if (name === 'hasOwnProperty') {
1502    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1503  }
1504}
1505
1506/**
1507 * Return the value accessible from the object by path. Any undefined traversals are ignored
1508 * @param {Object} obj starting object
1509 * @param {String} path path to traverse
1510 * @param {boolean} [bindFnToScope=true]
1511 * @returns {Object} value as accessible by path
1512 */
1513//TODO(misko): this function needs to be removed
1514function getter(obj, path, bindFnToScope) {
1515  if (!path) return obj;
1516  var keys = path.split('.');
1517  var key;
1518  var lastInstance = obj;
1519  var len = keys.length;
1520
1521  for (var i = 0; i < len; i++) {
1522    key = keys[i];
1523    if (obj) {
1524      obj = (lastInstance = obj)[key];
1525    }
1526  }
1527  if (!bindFnToScope && isFunction(obj)) {
1528    return bind(lastInstance, obj);
1529  }
1530  return obj;
1531}
1532
1533/**
1534 * Return the DOM siblings between the first and last node in the given array.
1535 * @param {Array} array like object
1536 * @returns {DOMElement}
1536 object containing the elements
1537 */
1538function getBlockElements(nodes) {
1539  var startNode = nodes[0],
1540      endNode = nodes[nodes.length - 1];
1541  if (startNode === endNode) {
1542    return jqLite(startNode);
1543  }
1544
1545  var element = startNode;
1546  var elements = [element];
1547
1548  do {
1549    element = element.nextSibling;
1550    if (!element) break;
1551    elements.push(element);
1552  } while (element !== endNode);
1553
1554  return jqLite(elements);
1555}
1556
1557/**
1558 * @ngdoc type
1559 * @name angular.Module
1560 * @module ng
1561 * @description
1562 *
1563 * Interface for configuring angular {@link angular.module modules}.
1564 */
1565
1566function setupModuleLoader(window) {
1567
1568  var $injectorMinErr = minErr('$injector');
1569  var ngMinErr = minErr('ng');
1570
1571  function ensure(obj, name, factory) {
1572    return obj[name] || (obj[name] = factory());
1573  }
1574
1575  var angular = ensure(window, 'angular', Object);
1576
1577  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1578  angular.$$minErr = angular.$$minErr || minErr;
1579
1580  return ensure(angular, 'module', function() {
1581    /** @type {Object.<string, angular.Module>} */
1582    var modules = {};
1583
1584    /**
1585     * @ngdoc function
1586     * @name angular.module
1587     * @module ng
1588     * @description
1589     *
1590     * The `angular.module` is a global place for creating, registering and retrieving Angular
1591     * modules.
1592     * All modules (angular core or 3rd party) that should be available to an application must be
1593     * registered using this mechanism.
1594     *
1595     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1596     * existing module (the name passed as the first argument to `module`) is retrieved.
1597     *
1598     *
1599     * # Module
1600     *
1601     * A module is a collection of services, directives, controllers, filters, and configuration information.
1602     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1603     *
1604     * ```js
1605     * // Create a new module
1606     * var myModule = angular.module('myModule', []);
1607     *
1608     * // register a new service
1609     * myModule.value('appName', 'MyCoolApp');
1610     *
1611     * // configure existing services inside initialization blocks.
1612     * myModule.config(['$locationProvider', function($locationProvider) {
1613     *   // Configure existing providers
1614     *   $locationProvider.hashPrefix('!');
1615     * }]);
1616     * ```
1617     *
1618     * Then you can create an injector and load your modules like this:
1619     *
1620     * ```js
1621     * var injector = angular.injector(['ng', 'myModule'])
1622     * ```
1623     *
1624     * However it's more likely that you'll just use
1625     * {@link ng.directive:ngApp ngApp} or
1626     * {@link angular.bootstrap} to simplify this process for you.
1627     *
1628     * @param {!string} name The name of the module to create or retrieve.
1629     * @param {!Array.<string>=} requires If specified then new module is being created. If
1630     *        unspecified then the module is being retrieved for further configuration.
1631     * @param {Function=} configFn Optional configuration function for the module. Same as
1632     *        {@link angular.Module#config Module#config()}.
1633     * @returns {module} new module with the {@link angular.Module} api.
1634     */
1635    return function module(name, requires, configFn) {
1636      var assertNotHasOwnProperty = function(name, context) {
1637        if (name === 'hasOwnProperty') {
1638          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1639        }
1640      };
1641
1642      assertNotHasOwnProperty(name, 'module');
1643      if (requires && modules.hasOwnProperty(name)) {
1644        modules[name] = null;
1645      }
1646      return ensure(modules, name, function() {
1647        if (!requires) {
1648          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1649             "the module name or forgot to load it. If registering a module ensure that you " +
1650             "specify the dependencies as the second argument.", name);
1651        }
1652
1653        /** @type {!Array.<Array.<*>>} */
1654        var invokeQueue = [];
1655
1656        /** @type {!Array.<Function>} */
1657        var runBlocks = [];
1658
1659        var config = invokeLater('$injector', 'invoke');
1660
1661        /** @type {angular.Module} */
1662        var moduleInstance = {
1663          // Private state
1664          _invokeQueue: invokeQueue,
1665          _runBlocks: runBlocks,
1666
1667          /**
1668           * @ngdoc property
1669           * @name angular.Module#requires
1670           * @module ng
1671           * @returns {Array.<string>} List of module names which must be loaded before this module.
1672           * @description
1673           * Holds the list of modules which the injector will load before the current module is
1674           * loaded.
1675           */
1676          requires: requires,
1677
1678          /**
1679           * @ngdoc property
1680           * @name angular.Module#name
1681           * @module ng
1682           * @returns {string} Name of the module.
1683           * @description
1684           */
1685          name: name,
1686
1687
1688          /**
1689           * @ngdoc method
1690           * @name angular.Module#provider
1691           * @module ng
1692           * @param {string} name service name
1693           * @param {Function} providerType Construction function for creating new instance of the
1694           *                                service.
1695           * @description
1696           * See {@link auto.$provide#provider $provide.provider()}.
1697           */
1698          provider: invokeLater('$provide', 'provider'),
1699
1700          /**
1701           * @ngdoc method
1702           * @name angular.Module#factory
1703           * @module ng
1704           * @param {string} name service name
1705           * @param {Function} providerFunction Function for creating new instance of the service.
1706           * @description
1707           * See {@link auto.$provide#factory $provide.factory()}.
1708           */
1709          factory: invokeLater('$provide', 'factory'),
1710
1711          /**
1712           * @ngdoc method
1713           * @name angular.Module#service
1714           * @module ng
1715           * @param {string} name service name
1716           * @param {Function} constructor A constructor function that will be instantiated.
1717           * @description
1718           * See {@link auto.$provide#service $provide.service()}.
1719           */
1720          service: invokeLater('$provide', 'service'),
1721
1722          /**
1723           * @ngdoc method
1724           * @name angular.Module#value
1725           * @module ng
1726           * @param {string} name service name
1727           * @param {*} object Service instance object.
1728           * @description
1729           * See {@link auto.$provide#value $provide.value()}.
1730           */
1731          value: invokeLater('$provide', 'value'),
1732
1733          /**
1734           * @ngdoc method
1735           * @name angular.Module#constant
1736           * @module ng
1737           * @param {string} name constant name
1738           * @param {*} object Constant value.
1739           * @description
1740           * Because the constant are fixed, they get applied before other provide methods.
1741           * See {@link auto.$provide#constant $provide.constant()}.
1742           */
1743          constant: invokeLater('$provide', 'constant', 'unshift'),
1744
1745          /**
1746           * @ngdoc method
1747           * @name angular.Module#animation
1748           * @module ng
1749           * @param {string} name animation name
1750           * @param {Function} animationFactory Factory function for creating new instance of an
1751           *                                    animation.
1752           * @description
1753           *
1754           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1755           *
1756           *
1757           * Defines an animation hook that can be later used with
1758           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1759           *
1760           * ```js
1761           * module.animation('.animation-name', function($inject1, $inject2) {
1762           *   return {
1763           *     eventName : function(element, done) {
1764           *       //code to run the animation
1765           *       //once complete, then run done()
1766           *       return function cancellationFunction(element) {
1767           *         //code to cancel the animation
1768           *       }
1769           *     }
1770           *   }
1771           * })
1772           * ```
1773           *
1774           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1775           * {@link ngAnimate ngAnimate module} for more information.
1776           */
1777          animation: invokeLater('$animateProvider', 'register'),
1778
1779          /**
1780           * @ngdoc method
1781           * @name angular.Module#filter
1782           * @module ng
1783           * @param {string} name Filter name.
1784           * @param {Function} filterFactory Factory function for creating new instance of filter.
1785           * @description
1786           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1787           */
1788          filter: invokeLater('$filterProvider', 'register'),
1789
1790          /**
1791           * @ngdoc method
1792           * @name angular.Module#controller
1793           * @module ng
1794           * @param {string|Object} name Controller name, or an object map of controllers where the
1795           *    keys are the names and the values are the constructors.
1796           * @param {Function} constructor Controller constructor function.
1797           * @description
1798           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1799           */
1800          controller: invokeLater('$controllerProvider', 'register'),
1801
1802          /**
1803           * @ngdoc method
1804           * @name angular.Module#directive
1805           * @module ng
1806           * @param {string|Object} name Directive name, or an object map of directives where the
1807           *    keys are the names and the values are the factories.
1808           * @param {Function} directiveFactory Factory function for creating new instance of
1809           * directives.
1810           * @description
1811           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1812           */
1813          directive: invokeLater('$compileProvider', 'directive'),
1814
1815          /**
1816           * @ngdoc method
1817           * @name angular.Module#config
1818           * @module ng
1819           * @param {Function} configFn Execute this function on module load. Useful for service
1820           *    configuration.
1821           * @description
1822           * Use this method to register work which needs to be performed on module loading.
1823           * For more about how to configure services, see
1824           * {@link providers#providers_provider-recipe Provider Recipe}.
1825           */
1826          config: config,
1827
1828          /**
1829           * @ngdoc method
1830           * @name angular.Module#run
1831           * @module ng
1832           * @param {Function} initializationFn Execute this function after injector creation.
1833           *    Useful for application initialization.
1834           * @description
1835           * Use this method to register work which should be performed when the injector is done
1836           * loading all modules.
1837           */
1838          run: function(block) {
1839            runBlocks.push(block);
1840            return this;
1841          }
1842        };
1843
1844        if (configFn) {
1845          config(configFn);
1846        }
1847
1848        return  moduleInstance;
1849
1850        /**
1851         * @param {string} provider
1852         * @param {string} method
1853         * @param {String=} insertMethod
1854         * @returns {angular.Module}
1855         */
1856        function invokeLater(provider, method, insertMethod) {
1857          return function() {
1858            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1859            return moduleInstance;
1860          };
1861        }
1862      });
1863    };
1864  });
1865
1866}
1867
1868/* global
1869    angularModule: true,
1870    version: true,
1871
1872    $LocaleProvider,
1873    $CompileProvider,
1874
1875    htmlAnchorDirective,
1876    inputDirective,
1877    inputDirective,
1878    formDirective,
1879    scriptDirective,
1880    selectDirective,
1881    styleDirective,
1882    optionDirective,
1883    ngBindDirective,
1884    ngBindHtmlDirective,
1885    ngBindTemplateDirective,
1886    ngClassDirective,
1887    ngClassEvenDirective,
1888    ngClassOddDirective,
1889    ngCspDirective,
1890    ngCloakDirective,
1891    ngControllerDirective,
1892    ngFormDirective,
1893    ngHideDirective,
1894    ngIfDirective,
1895    ngIncludeDirective,
1896    ngIncludeFillContentDirective,
1897    ngInitDirective,
1898    ngNonBindableDirective,
1899    ngPluralizeDirective,
1900    ngRepeatDirective,
1901    ngShowDirective,
1902    ngStyleDirective,
1903    ngSwitchDirective,
1904    ngSwitchWhenDirective,
1905    ngSwitchDefaultDirective,
1906    ngOptionsDirective,
1907    ngTranscludeDirective,
1908    ngModelDirective,
1909    ngListDirective,
1910    ngChangeDirective,
1911    requiredDirective,
1912    requiredDirective,
1913    ngValueDirective,
1914    ngAttributeAliasDirectives,
1915    ngEventDirectives,
1916
1917    $AnchorScrollProvider,
1918    $AnimateProvider,
1919    $BrowserProvider,
1920    $CacheFactoryProvider,
1921    $ControllerProvider,
1922    $DocumentProvider,
1923    $ExceptionHandlerProvider,
1924    $FilterProvider,
1925    $InterpolateProvider,
1926    $IntervalProvider,
1927    $HttpProvider,
1928    $HttpBackendProvider,
1929    $LocationProvider,
1930    $LogProvider,
1931    $ParseProvider,
1932    $RootScopeProvider,
1933    $QProvider,
1934    $$SanitizeUriProvider,
1935    $SceProvider,
1936    $SceDelegateProvider,
1937    $SnifferProvider,
1938    $TemplateCacheProvider,
1939    $TimeoutProvider,
1940    $$RAFProvider,
1941    $$AsyncCallbackProvider,
1942    $WindowProvider
1943*/
1944
1945
1946/**
1947 * @ngdoc object
1948 * @name angular.version
1949 * @module ng
1950 * @description
1951 * An object that contains information about the current AngularJS version. This object has the
1952 * following properties:
1953 *
1954 * - `full` – `{string}` – Full version string, such as "0.9.18".
1955 * - `major` – `{number}` – Major version number, such as "0".
1956 * - `minor` – `{number}` – Minor version number, such as "9".
1957 * - `dot` – `{number}` – Dot version number, such as "18".
1958 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1959 */
1960var version = {
1961  full: '1.2.19',    // all of these placeholder strings will be replaced by grunt's
1962  major: 1,    // package task
1963  minor: 2,
1964  dot: 19,
1965  codeName: 'precognitive-flashbacks'
1966};
1967
1968
1969function publishExternalAPI(angular){
1970  extend(angular, {
1971    'bootstrap': bootstrap,
1972    'copy': copy,
1973    'extend': extend,
1974    'equals': equals,
1975    'element': jqLite,
1976    'forEach': forEach,
1977    'injector': createInjector,
1978    'noop':noop,
1979    'bind':bind,
1980    'toJson': toJson,
1981    'fromJson': fromJson,
1982    'identity':identity,
1983    'isUndefined': isUndefined,
1984    'isDefined': isDefined,
1985    'isString': isString,
1986    'isFunction': isFunction,
1987    'isObject': isObject,
1988    'isNumber': isNumber,
1989    'isElement': isElement,
1990    'isArray': isArray,
1991    'version': version,
1992    'isDate': isDate,
1993    'lowercase': lowercase,
1994    'uppercase': uppercase,
1995    'callbacks': {counter: 0},
1996    '$$minErr': minErr,
1997    '$$csp': csp
1998  });
1999
2000  angularModule = setupModuleLoader(window);
2001  try {
2002    angularModule('ngLocale');
2003  } catch (e) {
2004    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2005  }
2006
2007  angularModule('ng', ['ngLocale'], ['$provide',
2008    function ngModule($provide) {
2009      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2010      $provide.provider({
2011        $$sanitizeUri: $$SanitizeUriProvider
2012      });
2013      $provide.provider('$compile', $CompileProvider).
2014        directive({
2015            a: htmlAnchorDirective,
2016            input: inputDirective,
2017            textarea: inputDirective,
2018            form: formDirective,
2019            script: scriptDirective,
2020            select: selectDirective,
2021            style: styleDirective,
2022            option: optionDirective,
2023            ngBind: ngBindDirective,
2024            ngBindHtml: ngBindHtmlDirective,
2025            ngBindTemplate: ngBindTemplateDirective,
2026            ngClass: ngClassDirective,
2027            ngClassEven: ngClassEvenDirective,
2028            ngClassOdd: ngClassOddDirective,
2029            ngCloak: ngCloakDirective,
2030            ngController: ngControllerDirective,
2031            ngForm: ngFormDirective,
2032            ngHide: ngHideDirective,
2033            ngIf: ngIfDirective,
2034            ngInclude: ngIncludeDirective,
2035            ngInit: ngInitDirective,
2036            ngNonBindable: ngNonBindableDirective,
2037            ngPluralize: ngPluralizeDirective,
2038            ngRepeat: ngRepeatDirective,
2039            ngShow: ngShowDirective,
2040            ngStyle: ngStyleDirective,
2041            ngSwitch: ngSwitchDirective,
2042            ngSwitchWhen: ngSwitchWhenDirective,
2043            ngSwitchDefault: ngSwitchDefaultDirective,
2044            ngOptions: ngOptionsDirective,
2045            ngTransclude: ngTranscludeDirective,
2046            ngModel: ngModelDirective,
2047            ngList: ngListDirective,
2048            ngChange: ngChangeDirective,
2049            required: requiredDirective,
2050            ngRequired: requiredDirective,
2051            ngValue: ngValueDirective
2052        }).
2053        directive({
2054          ngInclude: ngIncludeFillContentDirective
2055        }).
2056        directive(ngAttributeAliasDirectives).
2057        directive(ngEventDirectives);
2058      $provide.provider({
2059        $anchorScroll: $AnchorScrollProvider,
2060        $animate: $AnimateProvider,
2061        $browser: $BrowserProvider,
2062        $cacheFactory: $CacheFactoryProvider,
2063        $controller: $ControllerProvider,
2064        $document: $DocumentProvider,
2065        $exceptionHandler: $ExceptionHandlerProvider,
2066        $filter: $FilterProvider,
2067        $interpolate: $InterpolateProvider,
2068        $interval: $IntervalProvider,
2069        $http: $HttpProvider,
2070        $httpBackend: $HttpBackendProvider,
2071        $location: $LocationProvider,
2072        $log: $LogProvider,
2073        $parse: $ParseProvider,
2074        $rootScope: $RootScopeProvider,
2075        $q: $QProvider,
2076        $sce: $SceProvider,
2077        $sceDelegate: $SceDelegateProvider,
2078        $sniffer: $SnifferProvider,
2079        $templateCache: $TemplateCacheProvider,
2080        $timeout: $TimeoutProvider,
2081        $window: $WindowProvider,
2082        $$rAF: $$RAFProvider,
2083        $$asyncCallback : $$AsyncCallbackProvider
2084      });
2085    }
2086  ]);
2087}
2088
2089/* global
2090
2091  -JQLitePrototype,
2092  -addEventListenerFn,
2093  -removeEventListenerFn,
2094  -BOOLEAN_ATTR
2095*/
2096
2097//////////////////////////////////
2098//JQLite
2099//////////////////////////////////
2100
2101/**
2102 * @ngdoc function
2103 * @name angular.element
2104 * @module ng
2105 * @kind function
2106 *
2107 * @description
2108 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2109 *
2110 * If jQuery is available, `angular.element` is an alias for the
2111 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2112 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2113 *
2114 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2115 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2116 * commonly needed functionality with the goal of having a very small footprint.</div>
2117 *
2118 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2119 *
2120 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2121 * jqLite; they are never raw DOM references.</div>
2122 *
2123 * ## Angular's jqLite
2124 * jqLite provides only the following jQuery methods:
2125 *
2126 * - [`addClass()`](http://api.jquery.com/addClass/)
2127 * - [`after()`](http://api.jquery.com/after/)
2128 * - [`append()`](http://api.jquery.com/append/)
2129 * - [`attr()`](http://api.jquery.com/attr/)
2130 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2131 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2132 * - [`clone()`](http://api.jquery.com/clone/)
2133 * - [`contents()`](http://api.jquery.com/contents/)
2134 * - [`css()`](http://api.jquery.com/css/)
2135 * - [`data()`](http://api.jquery.com/data/)
2136 * - [`empty()`](http://api.jquery.com/empty/)
2137 * - [`eq()`](http://api.jquery.com/eq/)
2138 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2139 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2140 * - [`html()`](http://api.jquery.com/html/)
2141 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2142 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2143 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2144 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2145 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2146 * - [`prepend()`](http://api.jquery.com/prepend/)
2147 * - [`prop()`](http://api.jquery.com/prop/)
2148 * - [`ready()`](http://api.jquery.com/ready/)
2149 * - [`remove()`](http://api.jquery.com/remove/)
2150 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2151 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2152 * - [`removeData()`](http://api.jquery.com/removeData/)
2153 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2154 * - [`text()`](http://api.jquery.com/text/)
2155 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2156 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2157 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2158 * - [`val()`](http://api.jquery.com/val/)
2159 * - [`wrap()`](http://api.jquery.com/wrap/)
2160 *
2161 * ## jQuery/jqLite Extras
2162 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2163 *
2164 * ### Events
2165 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2165pis and fires this event
2166 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2167 *    element before it is removed.
2168 *
2169 * ### Methods
2170 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2171 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2172 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2173 *   `'ngModel'`).
2174 * - `injector()` - retrieves the injector of the current element or its parent.
2175 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2176 *   element or its parent.
2177 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2178 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2179 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2180 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2181 *   parent element is reached.
2182 *
2183 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2184 * @returns {Object} jQuery object.
2185 */
2186
2187JQLite.expando = 'ng339';
2188
2189var jqCache = JQLite.cache = {},
2190    jqId = 1,
2191    addEventListenerFn = (window.document.addEventListener
2192      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2193      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2194    removeEventListenerFn = (window.document.removeEventListener
2195      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2196      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2197
2198/*
2199 * !!! This is an undocumented "private" function !!!
2200 */
2201var jqData = JQLite._data = function(node) {
2202  //jQuery always returns an object on cache miss
2203  return this.cache[node[this.expando]] || {};
2204};
2205
2206function jqNextId() { return ++jqId; }
2207
2208
2209var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2210var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2211var jqLiteMinErr = minErr('jqLite');
2212
2213/**
2214 * Converts snake_case to camelCase.
2215 * Also there is special case for Moz prefix starting with upper case letter.
2216 * @param name Name to normalize
2217 */
2218function camelCase(name) {
2219  return name.
2220    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2221      return offset ? letter.toUpperCase() : letter;
2222    }).
2223    replace(MOZ_HACK_REGEXP, 'Moz$1');
2224}
2225
2226/////////////////////////////////////////////
2227// jQuery mutation patch
2228//
2229// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2230// $destroy event on all DOM nodes being removed.
2231//
2232/////////////////////////////////////////////
2233
2234function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2235  var originalJqFn = jQuery.fn[name];
2236  originalJqFn = originalJqFn.$original || originalJqFn;
2237  removePatch.$original = originalJqFn;
2238  jQuery.fn[name] = removePatch;
2239
2240  function removePatch(param) {
2241    // jshint -W040
2242    var list = filterElems && param ? [this.filter(param)] : [this],
2243        fireEvent = dispatchThis,
2244        set, setIndex, setLength,
2245        element, childIndex, childLength, children;
2246
2247    if (!getterIfNoArguments || param != null) {
2248      while(list.length) {
2249        set = list.shift();
2250        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2251          element = jqLite(set[setIndex]);
2252          if (fireEvent) {
2253            element.triggerHandler('$destroy');
2254          } else {
2255            fireEvent = !fireEvent;
2256          }
2257          for(childIndex = 0, childLength = (children = element.children()).length;
2258              childIndex < childLength;
2259              childIndex++) {
2260            list.push(jQuery(children[childIndex]));
2261          }
2262        }
2263      }
2264    }
2265    return originalJqFn.apply(this, arguments);
2266  }
2267}
2268
2269var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2270var HTML_REGEXP = /<|&#?\w+;/;
2271var TAG_NAME_REGEXP = /<([\w:]+)/;
2272var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2273
2274var wrapMap = {
2275  'option': [1, '<select multiple="multiple">', '</select>'],
2276
2277  'thead': [1, '<table>', '</table>'],
2278  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2279  'tr': [2, '<table><tbody>', '</tbody></table>'],
2280  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2281  '_default': [0, "", ""]
2282};
2283
2284wrapMap.optgroup = wrapMap.option;
2285wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2286wrapMap.th = wrapMap.td;
2287
2288function jqLiteIsTextNode(html) {
2289  return !HTML_REGEXP.test(html);
2290}
2291
2292function jqLiteBuildFragment(html, context) {
2293  var elem, tmp, tag, wrap,
2294      fragment = context.createDocumentFragment(),
2295      nodes = [], i, j, jj;
2296
2297  if (jqLiteIsTextNode(html)) {
2298    // Convert non-html into a text node
2299    nodes.push(context.createTextNode(html));
2300  } else {
2301    tmp = fragment.appendChild(context.createElement('div'));
2302    // Convert html into DOM nodes
2303    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2304    wrap = wrapMap[tag] || wrapMap._default;
2305    tmp.innerHTML = '<div>&#160;</div>' +
2306      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2307    tmp.removeChild(tmp.firstChild);
2308
2309    // Descend through wrappers to the right content
2310    i = wrap[0];
2311    while (i--) {
2312      tmp = tmp.lastChild;
2313    }
2314
2315    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
2316
2317    tmp = fragment.firstChild;
2318    tmp.textContent = "";
2319  }
2320
2321  // Remove wrapper from fragment
2322  fragment.textContent = "";
2323  fragment.innerHTML = ""; // Clear inner HTML
2324  return nodes;
2325}
2326
2327function jqLiteParseHTML(html, context) {
2328  context = context || document;
2329  var parsed;
2330
2331  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2332    return [context.createElement(parsed[1])];
2333  }
2334
2335  return jqLiteBuildFragment(html, context);
2336}
2337
2338/////////////////////////////////////////////
2339function JQLite(element) {
2340  if (element instanceof JQLite) {
2341    return element;
2342  }
2343  if (isString(element)) {
2344    element = trim(element);
2345  }
2346  if (!(this instanceof JQLite)) {
2347    if (isString(element) && element.charAt(0) != '<') {
2348      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2349    }
2350    return new JQLite(element);
2351  }
2352
2353  if (isString(element)) {
2354    jqLiteAddNodes(this, jqLiteParseHTML(element));
2355    var fragment = jqLite(document.createDocumentFragment());
2356    fragment.append(this);
2357  } else {
2358    jqLiteAddNodes(this, element);
2359  }
2360}
2361
2362function jqLiteClone(element) {
2363  return element.cloneNode(true);
2364}
2365
2366function jqLiteDealoc(element){
2367  jqLiteRemoveData(element);
2368  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2369    jqLiteDealoc(children[i]);
2370  }
2371}
2372
2373function jqLiteOff(element, type, fn, unsupported) {
2374  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2375
2376  var events = jqLiteExpandoStore(element, 'events'),
2377      handle = jqLiteExpandoStore(element, 'handle');
2378
2379  if (!handle) return; //no listeners registered
2380
2381  if (isUndefined(type)) {
2382    forEach(events, function(eventHandler, type) {
2383      removeEventListenerFn(element, type, eventHandler);
2384      delete events[type];
2385    });
2386  } else {
2387    forEach(type.split(' '), function(type) {
2388      if (isUndefined(fn)) {
2389        removeEventListenerFn(element, type, events[type]);
2390        delete events[type];
2391      } else {
2392        arrayRemove(events[type] || [], fn);
2393      }
2394    });
2395  }
2396}
2397
2398function jqLiteRemoveData(element, name) {
2399  var expandoId = element.ng339,
2400      expandoStore = jqCache[expandoId];
2401
2402  if (expandoStore) {
2403    if (name) {
2404      delete jqCache[expandoId].data[name];
2405      return;
2406    }
2407
2408    if (expandoStore.handle) {
2409      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2410      jqLiteOff(element);
2411    }
2412    delete jqCache[expandoId];
2413    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2414  }
2415}
2416
2417function jqLiteExpandoStore(element, key, value) {
2418  var expandoId = element.ng339,
2419      expandoStore = jqCache[expandoId || -1];
2420
2421  if (isDefined(value)) {
2422    if (!expandoStore) {
2423      element.ng339 = expandoId = jqNextId();
2424      expandoStore = jqCache[expandoId] = {};
2425    }
2426    expandoStore[key] = value;
2427  } else {
2428    return expandoStore && expandoStore[key];
2429  }
2430}
2431
2432function jqLiteData(element, key, value) {
2433  var data = jqLiteExpandoStore(element, 'data'),
2434      isSetter = isDefined(value),
2435      keyDefined = !isSetter && isDefined(key),
2436      isSimpleGetter = keyDefined && !isObject(key);
2437
2438  if (!data && !isSimpleGetter) {
2439    jqLiteExpandoStore(element, 'data', data = {});
2440  }
2441
2442  if (isSetter) {
2443    data[key] = value;
2444  } else {
2445    if (keyDefined) {
2446      if (isSimpleGetter) {
2447        // don't create data in this case.
2448        return data && data[key];
2449      } else {
2450        extend(data, key);
2451      }
2452    } else {
2453      return data;
2454    }
2455  }
2456}
2457
2458function jqLiteHasClass(element, selector) {
2459  if (!element.getAttribute) return false;
2460  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2461      indexOf( " " + selector + " " ) > -1);
2462}
2463
2464function jqLiteRemoveClass(element, cssClasses) {
2465  if (cssClasses && element.setAttribute) {
2466    forEach(cssClasses.split(' '), function(cssClass) {
2467      element.setAttribute('class', trim(
2468          (" " + (element.getAttribute('class') || '') + " ")
2469          .replace(/[\n\t]/g, " ")
2470          .replace(" " + trim(cssClass) + " ", " "))
2471      );
2472    });
2473  }
2474}
2475
2476function jqLiteAddClass(element, cssClasses) {
2477  if (cssClasses && element.setAttribute) {
2478    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2479                            .replace(/[\n\t]/g, " ");
2480
2481    forEach(cssClasses.split(' '), function(cssClass) {
2482      cssClass = trim(cssClass);
2483      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2484        existingClasses += cssClass + ' ';
2485      }
2486    });
2487
2488    element.setAttribute('class', trim(existingClasses));
2489  }
2490}
2491
2492function jqLiteAddNodes(root, elements) {
2493  if (elements) {
2494    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2495      ? elements
2496      : [ elements ];
2497    for(var i=0; i < elements.length; i++) {
2498      root.push(elements[i]);
2499    }
2500  }
2501}
2502
2503function jqLiteController(element, name) {
2504  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2505}
2506
2507function jqLiteInheritedData(element, name, value) {
2508  element = jqLite(element);
2509
2510  // if element is the document object work with the html element instead
2511  // this makes $(document).scope() possible
2512  if(element[0].nodeType == 9) {
2513    element = element.find('html');
2514  }
2515  var names = isArray(name) ? name : [name];
2516
2517  while (element.length) {
2518    var node = element[0];
2519    for (var i = 0, ii = names.length; i < ii; i++) {
2520      if ((value = element.data(names[i])) !== undefined) return value;
2521    }
2522
2523    // If dealing with a document fragment node with a host element, and no parent, use the host
2524    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2525    // to lookup parent controllers.
2526    element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
2527  }
2528}
2529
2530function jqLiteEmpty(element) {
2531  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2532    jqLiteDealoc(childNodes[i]);
2533  }
2534  while (element.firstChild) {
2535    element.removeChild(element.firstChild);
2536  }
2537}
2538
2539//////////////////////////////////////////
2540// Functions which are declared directly.
2541//////////////////////////////////////////
2542var JQLitePrototype = JQLite.prototype = {
2543  ready: function(fn) {
2544    var fired = false;
2545
2546    function trigger() {
2547      if (fired) return;
2548      fired = true;
2549      fn();
2550    }
2551
2552    // check if document already is loaded
2553    if (document.readyState === 'complete'){
2554      setTimeout(trigger);
2555    } else {
2556      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2557      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2558      // jshint -W064
2559      JQLite(window).on('load', trigger); // fallback to window.onload for others
2560      // jshint +W064
2561    }
2562  },
2563  toString: function() {
2564    var value = [];
2565    forEach(this, function(e){ value.push('' + e);});
2566    return '[' + value.join(', ') + ']';
2567  },
2568
2569  eq: function(index) {
2570      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2571  },
2572
2573  length: 0,
2574  push: push,
2575  sort: [].sort,
2576  splice: [].splice
2577};
2578
2579//////////////////////////////////////////
2580// Functions iterating getter/setters.
2581// these functions return self on setter and
2582// value on get.
2583//////////////////////////////////////////
2584var BOOLEAN_ATTR = {};
2585forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2586  BOOLEAN_ATTR[lowercase(value)] = value;
2587});
2588var BOOLEAN_ELEMENTS = {};
2589forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2590  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2591});
2592
2593function getBooleanAttrName(element, name) {
2594  // check dom last since we will most likely fail on name
2595  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2596
2597  // booleanAttr is here twice to minimize DOM access
2598  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2599}
2600
2601forEach({
2602  data: jqLiteData,
2603  inheritedData: jqLiteInheritedData,
2604
2605  scope: function(element) {
2606    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2607    return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2608  },
2609
2610  isolateScope: function(element) {
2611    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2612    return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
2613  },
2614
2615  controller: jqLiteController,
2616
2617  injector: function(element) {
2618    return jqLiteInheritedData(element, '$injector');
2619  },
2620
2621  removeAttr: function(element,name) {
2622    element.removeAttribute(name);
2623  },
2624
2625  hasClass: jqLiteHasClass,
2626
2627  css: function(element, name, value) {
2628    name = camelCase(name);
2629
2630    if (isDefined(value)) {
2631      element.style[name] = value;
2632    } else {
2633      var val;
2634
2635      if (msie <= 8) {
2636        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2637        val = element.currentStyle && element.currentStyle[name];
2638        if (val === '') val = 'auto';
2639      }
2640
2641      val = val || element.style[name];
2642
2643      if (msie <= 8) {
2644        // jquery weirdness :-/
2645        val = (val === '') ? undefined : val;
2646      }
2647
2648      return  val;
2649    }
2650  },
2651
2652  attr: function(element, name, value){
2653    var lowercasedName = lowercase(name);
2654    if (BOOLEAN_ATTR[lowercasedName]) {
2655      if (isDefined(value)) {
2656        if (!!value) {
2657          element[name] = true;
2658          element.setAttribute(name, lowercasedName);
2659        } else {
2660          element[name] = false;
2661          element.removeAttribute(lowercasedName);
2662        }
2663      } else {
2664        return (element[name] ||
2665                 (element.attributes.getNamedItem(name)|| noop).specified)
2666               ? lowercasedName
2667               : undefined;
2668      }
2669    } else if (isDefined(value)) {
2670      element.setAttribute(name, value);
2671    } else if (element.getAttribute) {
2672      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2673      // some elements (e.g. Document) don't have get attribute, so return undefined
2674      var ret = element.getAttribute(name, 2);
2675      // normalize non-existing attributes to undefined (as jQuery)
2676      return ret === null ? undefined : ret;
2677    }
2678  },
2679
2680  prop: function(element, name, value) {
2681    if (isDefined(value)) {
2682      element[name] = value;
2683    } else {
2684      return element[name];
2685    }
2686  },
2687
2688  text: (function() {
2689    var NODE_TYPE_TEXT_PROPERTY = [];
2690    if (msie < 9) {
2691      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2692      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2693    } else {
2694      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2695      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2696    }
2697    getText.$dv = '';
2698    return getText;
2699
2700    function getText(element, value) {
2701      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2702      if (isUndefined(value)) {
2703        return textProp ? element[textProp] : '';
2704      }
2705      element[textProp] = value;
2706    }
2707  })(),
2708
2709  val: function(element, value) {
2710    if (isUndefined(value)) {
2711      if (nodeName_(element) === 'SELECT' && element.multiple) {
2712        var result = [];
2713        forEach(element.options, function (option) {
2714          if (option.selected) {
2715            result.push(option.value || option.text);
2716          }
2717        });
2718        return result.length === 0 ? null : result;
2719      }
2720      return element.value;
2721    }
2722    element.value = value;
2723  },
2724
2725  html: function(element, value) {
2726    if (isUndefined(value)) {
2727      return element.innerHTML;
2728    }
2729    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2730      jqLiteDealoc(childNodes[i]);
2731    }
2732    element.innerHTML = value;
2733  },
2734
2735  empty: jqLiteEmpty
2736}, function(fn, name){
2737  /**
2738   * Properties: writes return selection, reads return first value
2739   */
2740  JQLite.prototype[name] = function(arg1, arg2) {
2741    var i, key;
2742    var nodeCount = this.length;
2743
2744    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2745    // in a way that survives minification.
2746    // jqLiteEmpty takes no arguments but is a setter.
2747    if (fn !== jqLiteEmpty &&
2748        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2749      if (isObject(arg1)) {
2750
2751        // we are a write, but the object properties are the key/values
2752        for (i = 0; i < nodeCount; i++) {
2753          if (fn === jqLiteData) {
2754            // data() takes the whole object in jQuery
2755            fn(this[i], arg1);
2756          } else {
2757            for (key in arg1) {
2758              fn(this[i], key, arg1[key]);
2759            }
2760          }
2761        }
2762        // return self for chaining
2763        return this;
2764      } else {
2765        // we are a read, so read the first child.
2766        // TODO: do we still need this?
2767        var value = fn.$dv;
2768        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2769        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2770        for (var j = 0; j < jj; j++) {
2771          var nodeValue = fn(this[j], arg1, arg2);
2772          value = value ? value + nodeValue : nodeValue;
2773        }
2774        return value;
2775      }
2776    } else {
2777      // we are a write, so apply to all children
2778      for (i = 0; i < nodeCount; i++) {
2779        fn(this[i], arg1, arg2);
2780      }
2781      // return self for chaining
2782      return this;
2783    }
2784  };
2785});
2786
2787function createEventHandler(element, events) {
2788  var eventHandler = function (event, type) {
2789    if (!event.preventDefault) {
2790      event.preventDefault = function() {
2791        event.returnValue = false; //ie
2792      };
2793    }
2794
2795    if (!event.stopPropagation) {
2796      event.stopPropagation = function() {
2797        event.cancelBubble = true; //ie
2798      };
2799    }
2800
2801    if (!event.target) {
2802      event.target = event.srcElement || document;
2803    }
2804
2805    if (isUndefined(event.defaultPrevented)) {
2806      var prevent = event.preventDefault;
2807      event.preventDefault = function() {
2808        event.defaultPrevented = true;
2809        prevent.call(event);
2810      };
2811      event.defaultPrevented = false;
2812    }
2813
2814    event.isDefaultPrevented = function() {
2815      return event.defaultPrevented || event.returnValue === false;
2816    };
2817
2818    // Copy event handlers in case event handlers array is modified during execution.
2819    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2820
2821    forEach(eventHandlersCopy, function(fn) {
2822      fn.call(element, event);
2823    });
2824
2825    // Remove monkey-patched methods (IE),
2826    // as they would cause memory leaks in IE8.
2827    if (msie <= 8) {
2828      // IE7/8 does not allow to delete property on native object
2829      event.preventDefault = null;
2830      event.stopPropagation = null;
2831      event.isDefaultPrevented = null;
2832    } else {
2833      // It shouldn't affect normal browsers (native methods are defined on prototype).
2834      delete event.preventDefault;
2835      delete event.stopPropagation;
2836      delete event.isDefaultPrevented;
2837    }
2838  };
2839  eventHandler.elem = element;
2840  return eventHandler;
2841}
2842
2843//////////////////////////////////////////
2844// Functions iterating traversal.
2845// These functions chain results into a single
2846// selector.
2847//////////////////////////////////////////
2848forEach({
2849  removeData: jqLiteRemoveData,
2850
2851  dealoc: jqLiteDealoc,
2852
2853  on: function onFn(element, type, fn, unsupported){
2854    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2855
2856    var events = jqLiteExpandoStore(element, 'events'),
2857        handle = jqLiteExpandoStore(element, 'handle');
2858
2859    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2860    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2861
2862    forEach(type.split(' '), function(type){
2863      var eventFns = events[type];
2864
2865      if (!eventFns) {
2866        if (type == 'mouseenter' || type == 'mouseleave') {
2867          var contains = document.body.contains || document.body.compareDocumentPosition ?
2868          function( a, b ) {
2869            // jshint bitwise: false
2870            var adown = a.nodeType === 9 ? a.documentElement : a,
2871            bup = b && b.parentNode;
2872            return a === bup || !!( bup && bup.nodeType === 1 && (
2873              adown.contains ?
2874              adown.contains( bup ) :
2875              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2876              ));
2877            } :
2878            function( a, b ) {
2879              if ( b ) {
2880                while ( (b = b.parentNode) ) {
2881                  if ( b === a ) {
2882                    return true;
2883                  }
2884                }
2885              }
2886              return false;
2887            };
2888
2889          events[type] = [];
2890
2891          // Refer to jQuery's implementation of mouseenter & mouseleave
2892          // Read about mouseenter and mouseleave:
2893          // http://www.quirksmode.org/js/events_mouse.html#link8
2894          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2895
2896          onFn(element, eventmap[type], function(event) {
2897            var target = this, related = event.relatedTarget;
2898            // For mousenter/leave call the handler if related is outside the target.
2899            // NB: No relatedTarget if the mouse left/entered the browser window
2900            if ( !related || (related !== target && !contains(target, related)) ){
2901              handle(event, type);
2902            }
2903          });
2904
2905        } else {
2906          addEventListenerFn(element, type, handle);
2907          events[type] = [];
2908        }
2909        eventFns = events[type];
2910      }
2911      eventFns.push(fn);
2912    });
2913  },
2914
2915  off: jqLiteOff,
2916
2917  one: function(element, type, fn) {
2918    element = jqLite(element);
2919
2920    //add the listener twice so that when it is called
2921    //you can remove the original function and still be
2922    //able to call element.off(ev, fn) normally
2923    element.on(type, function onFn() {
2924      element.off(type, fn);
2925      element.off(type, onFn);
2926    });
2927    element.on(type, fn);
2928  },
2929
2930  replaceWith: function(element, replaceNode) {
2931    var index, parent = element.parentNode;
2932    jqLiteDealoc(element);
2933    forEach(new JQLite(replaceNode), function(node){
2934      if (index) {
2935        parent.insertBefore(node, index.nextSibling);
2936      } else {
2937        parent.replaceChild(node, element);
2938      }
2939      index = node;
2940    });
2941  },
2942
2943  children: function(element) {
2944    var children = [];
2945    forEach(element.childNodes, function(element){
2946      if (element.nodeType === 1)
2947        children.push(element);
2948    });
2949    return children;
2950  },
2951
2952  contents: function(element) {
2953    return element.contentDocument || element.childNodes || [];
2954  },
2955
2956  append: function(element, node) {
2957    forEach(new JQLite(node), function(child){
2958      if (element.nodeType === 1 || element.nodeType === 11) {
2959        element.appendChild(child);
2960      }
2961    });
2962  },
2963
2964  prepend: function(element, node) {
2965    if (element.nodeType === 1) {
2966      var index = element.firstChild;
2967      forEach(new JQLite(node), function(child){
2968        element.insertBefore(child, index);
2969      });
2970    }
2971  },
2972
2973  wrap: function(element, wrapNode) {
2974    wrapNode = jqLite(wrapNode)[0];
2975    var parent = element.parentNode;
2976    if (parent) {
2977      parent.replaceChild(wrapNode, element);
2978    }
2979    wrapNode.appendChild(element);
2980  },
2981
2982  remove: function(element) {
2983    jqLiteDealoc(element);
2984    var parent = element.parentNode;
2985    if (parent) parent.removeChild(element);
2986  },
2987
2988  after: function(element, newElement) {
2989    var index = element, parent = element.parentNode;
2990    forEach(new JQLite(newElement), function(node){
2991      parent.insertBefore(node, index.nextSibling);
2992      index = node;
2993    });
2994  },
2995
2996  addClass: jqLiteAddClass,
2997  removeClass: jqLiteRemoveClass,
2998
2999  toggleClass: function(element, selector, condition) {
3000    if (selector) {
3001      forEach(selector.split(' '), function(className){
3002        var classCondition = condition;
3003        if (isUndefined(classCondition)) {
3004          classCondition = !jqLiteHasClass(element, className);
3005        }
3006        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3007      });
3008    }
3009  },
3010
3011  parent: function(element) {
3012    var parent = element.parentNode;
3013    return parent && parent.nodeType !== 11 ? parent : null;
3014  },
3015
3016  next: function(element) {
3017    if (element.nextElementSibling) {
3018      return element.nextElementSibling;
3019    }
3020
3021    // IE8 doesn't have nextElementSibling
3022    var elm = element.nextSibling;
3023    while (elm != null && elm.nodeType !== 1) {
3024      elm = elm.nextSibling;
3025    }
3026    return elm;
3027  },
3028
3029  find: function(element, selector) {
3030    if (element.getElementsByTagName) {
3031      return element.getElementsByTagName(selector);
3032    } else {
3033      return [];
3034    }
3035  },
3036
3037  clone: jqLiteClone,
3038
3039  triggerHandler: function(element, eventName, eventData) {
3040    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
3041
3042    eventData = eventData || [];
3043
3044    var event = [{
3045      preventDefault: noop,
3046      stopPropagation: noop
3047    }];
3048
3049    forEach(eventFns, function(fn) {
3050      fn.apply(element, event.concat(eventData));
3051    });
3052  }
3053}, function(fn, name){
3054  /**
3055   * chaining functions
3056   */
3057  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3058    var value;
3059    for(var i=0; i < this.length; i++) {
3060      if (isUndefined(value)) {
3061        value = fn(this[i], arg1, arg2, arg3);
3062        if (isDefined(value)) {
3063          // any function which returns a value needs to be wrapped
3064          value = jqLite(value);
3065        }
3066      } else {
3067        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3068      }
3069    }
3070    return isDefined(value) ? value : this;
3071  };
3072
3073  // bind legacy bind/unbind to on/off
3074  JQLite.prototype.bind = JQLite.prototype.on;
3075  JQLite.prototype.unbind = JQLite.prototype.off;
3076});
3077
3078/**
3079 * Computes a hash of an 'obj'.
3080 * Hash of a:
3081 *  string is string
3082 *  number is number as string
3083 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3084 *         that is also assigned to the $$hashKey property of the object.
3085 *
3086 * @param obj
3087 * @returns {string} hash string such that the same input will have the same hash string.
3088 *         The resulting string key is in 'type:hashKey' format.
3089 */
3090function hashKey(obj, nextUidFn) {
3091  var objType = typeof obj,
3092      key;
3093
3094  if (objType == 'function' || (objType == 'object' && obj !== null)) {
3095    if (typeof (key = obj.$$hashKey) == 'function') {
3096      // must invoke on object to keep the right this
3097      key = obj.$$hashKey();
3098    } else if (key === undefined) {
3099      key = obj.$$hashKey = (nextUidFn || nextUid)();
3100    }
3101  } else {
3102    key = obj;
3103  }
3104
3105  return objType + ':' + key;
3106}
3107
3108/**
3109 * HashMap which can use objects as keys
3110 */
3111function HashMap(array, isolatedUid) {
3112  if (isolatedUid) {
3113    var uid = 0;
3114    this.nextUid = function() {
3115      return ++uid;
3116    };
3117  }
3118  forEach(array, this.put, this);
3119}
3120HashMap.prototype = {
3121  /**
3122   * Store key value pair
3123   * @param key key to store can be any type
3124   * @param value value to store can be any type
3125   */
3126  put: function(key, value) {
3127    this[hashKey(key, this.nextUid)] = value;
3128  },
3129
3130  /**
3131   * @param key
3132   * @returns {Object} the value for the key
3133   */
3134  get: function(key) {
3135    return this[hashKey(key, this.nextUid)];
3136  },
3137
3138  /**
3139   * Remove the key/value pair
3140   * @param key
3141   */
3142  remove: function(key) {
3143    var value = this[key = hashKey(key, this.nextUid)];
3144    delete this[key];
3145    return value;
3146  }
3147};
3148
3149/**
3150 * @ngdoc function
3151 * @module ng
3152 * @name angular.injector
3153 * @kind function
3154 *
3155 * @description
3156 * Creates an injector function that can be used for retrieving services as well as for
3157 * dependency injection (see {@link guide/di dependency injection}).
3158 *
3159
3160 * @param {Array.<string|Function>}
3160 modules A list of module functions or their aliases. See
3161 *        {@link angular.module}. The `ng` module must be explicitly added.
3162 * @returns {function()} Injector function. See {@link auto.$injector $injector}.
3163 *
3164 * @example
3165 * Typical usage
3166 * ```js
3167 *   // create an injector
3168 *   var $injector = angular.injector(['ng']);
3169 *
3170 *   // use the injector to kick off your application
3171 *   // use the type inference to auto inject arguments, or use implicit injection
3172 *   $injector.invoke(function($rootScope, $compile, $document){
3173 *     $compile($document)($rootScope);
3174 *     $rootScope.$digest();
3175 *   });
3176 * ```
3177 *
3178 * Sometimes you want to get access to the injector of a currently running Angular app
3179 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3180 * application has been bootstrapped. You can do this using the extra `injector()` added
3181 * to JQuery/jqLite elements. See {@link angular.element}.
3182 *
3183 * *This is fairly rare but could be the case if a third party library is injecting the
3184 * markup.*
3185 *
3186 * In the following example a new block of HTML containing a `ng-controller`
3187 * directive is added to the end of the document body by JQuery. We then compile and link
3188 * it into the current AngularJS scope.
3189 *
3190 * ```js
3191 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3192 * $(document.body).append($div);
3193 *
3194 * angular.element(document).injector().invoke(function($compile) {
3195 *   var scope = angular.element($div).scope();
3196 *   $compile($div)(scope);
3197 * });
3198 * ```
3199 */
3200
3201
3202/**
3203 * @ngdoc module
3204 * @name auto
3205 * @description
3206 *
3207 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3208 */
3209
3210var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3211var FN_ARG_SPLIT = /,/;
3212var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3213var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3214var $injectorMinErr = minErr('$injector');
3215function annotate(fn) {
3216  var $inject,
3217      fnText,
3218      argDecl,
3219      last;
3220
3221  if (typeof fn === 'function') {
3222    if (!($inject = fn.$inject)) {
3223      $inject = [];
3224      if (fn.length) {
3225        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3226        argDecl = fnText.match(FN_ARGS);
3227        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3228          arg.replace(FN_ARG, function(all, underscore, name){
3229            $inject.push(name);
3230          });
3231        });
3232      }
3233      fn.$inject = $inject;
3234    }
3235  } else if (isArray(fn)) {
3236    last = fn.length - 1;
3237    assertArgFn(fn[last], 'fn');
3238    $inject = fn.slice(0, last);
3239  } else {
3240    assertArgFn(fn, 'fn', true);
3241  }
3242  return $inject;
3243}
3244
3245///////////////////////////////////////
3246
3247/**
3248 * @ngdoc service
3249 * @name $injector
3250 * @kind function
3251 *
3252 * @description
3253 *
3254 * `$injector` is used to retrieve object instances as defined by
3255 * {@link auto.$provide provider}, instantiate types, invoke methods,
3256 * and load modules.
3257 *
3258 * The following always holds true:
3259 *
3260 * ```js
3261 *   var $injector = angular.injector();
3262 *   expect($injector.get('$injector')).toBe($injector);
3263 *   expect($injector.invoke(function($injector){
3264 *     return $injector;
3265 *   }).toBe($injector);
3266 * ```
3267 *
3268 * # Injection Function Annotation
3269 *
3270 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3271 * following are all valid ways of annotating function with injection arguments and are equivalent.
3272 *
3273 * ```js
3274 *   // inferred (only works if code not minified/obfuscated)
3275 *   $injector.invoke(function(serviceA){});
3276 *
3277 *   // annotated
3278 *   function explicit(serviceA) {};
3279 *   explicit.$inject = ['serviceA'];
3280 *   $injector.invoke(explicit);
3281 *
3282 *   // inline
3283 *   $injector.invoke(['serviceA', function(serviceA){}]);
3284 * ```
3285 *
3286 * ## Inference
3287 *
3288 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3289 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3290 * minification, and obfuscation tools since these tools change the argument names.
3291 *
3292 * ## `$inject` Annotation
3293 * By adding an `$inject` property onto a function the injection parameters can be specified.
3294 *
3295 * ## Inline
3296 * As an array of injection names, where the last item in the array is the function to call.
3297 */
3298
3299/**
3300 * @ngdoc method
3301 * @name $injector#get
3302 *
3303 * @description
3304 * Return an instance of the service.
3305 *
3306 * @param {string} name The name of the instance to retrieve.
3307 * @return {*} The instance.
3308 */
3309
3310/**
3311 * @ngdoc method
3312 * @name $injector#invoke
3313 *
3314 * @description
3315 * Invoke the method and supply the method arguments from the `$injector`.
3316 *
3317 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3318 *   {@link guide/di $inject Annotation} rules.
3319 * @param {Object=} self The `this` for the invoked method.
3320 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3321 *                         object first, before the `$injector` is consulted.
3322 * @returns {*} the value returned by the invoked `fn` function.
3323 */
3324
3325/**
3326 * @ngdoc method
3327 * @name $injector#has
3328 *
3329 * @description
3330 * Allows the user to query if the particular service exists.
3331 *
3332 * @param {string} Name of the service to query.
3333 * @returns {boolean} returns true if injector has given service.
3334 */
3335
3336/**
3337 * @ngdoc method
3338 * @name $injector#instantiate
3339 * @description
3340 * Create a new instance of JS type. The method takes a constructor function, invokes the new
3341 * operator, and supplies all of the arguments to the constructor function as specified by the
3342 * constructor annotation.
3343 *
3344 * @param {Function} Type Annotated constructor function.
3345 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3346 * object first, before the `$injector` is consulted.
3347 * @returns {Object} new instance of `Type`.
3348 */
3349
3350/**
3351 * @ngdoc method
3352 * @name $injector#annotate
3353 *
3354 * @description
3355 * Returns an array of service names which the function is requesting for injection. This API is
3356 * used by the injector to determine which services need to be injected into the function when the
3357 * function is invoked. There are three ways in which the function can be annotated with the needed
3358 * dependencies.
3359 *
3360 * # Argument names
3361 *
3362 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3363 * by converting the function into a string using `toString()` method and extracting the argument
3364 * names.
3365 * ```js
3366 *   // Given
3367 *   function MyController($scope, $route) {
3368 *     // ...
3369 *   }
3370 *
3371 *   // Then
3372 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3373 * ```
3374 *
3375 * This method does not work with code minification / obfuscation. For this reason the following
3376 * annotation strategies are supported.
3377 *
3378 * # The `$inject` property
3379 *
3380 * If a function has an `$inject` property and its value is an array of strings, then the strings
3381 * represent names of services to be injected into the function.
3382 * ```js
3383 *   // Given
3384 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3385 *     // ...
3386 *   }
3387 *   // Define function dependencies
3388 *   MyController['$inject'] = ['$scope', '$route'];
3389 *
3390 *   // Then
3391 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3392 * ```
3393 *
3394 * # The array notation
3395 *
3396 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3397 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3398 * a way that survives minification is a better choice:
3399 *
3400 * ```js
3401 *   // We wish to write this (not minification / obfuscation safe)
3402 *   injector.invoke(function($compile, $rootScope) {
3403 *     // ...
3404 *   });
3405 *
3406 *   // We are forced to write break inlining
3407 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3408 *     // ...
3409 *   };
3410 *   tmpFn.$inject = ['$compile', '$rootScope'];
3411 *   injector.invoke(tmpFn);
3412 *
3413 *   // To better support inline function the inline annotation is supported
3414 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3415 *     // ...
3416 *   }]);
3417 *
3418 *   // Therefore
3419 *   expect(injector.annotate(
3420 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3421 *    ).toEqual(['$compile', '$rootScope']);
3422 * ```
3423 *
3424 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3425 * be retrieved as described above.
3426 *
3427 * @returns {Array.<string>} The names of the services which the function requires.
3428 */
3429
3430
3431
3432
3433/**
3434 * @ngdoc service
3435 * @name $provide
3436 *
3437 * @description
3438 *
3439 * The {@link auto.$provide $provide} service has a number of methods for registering components
3440 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3441 * {@link angular.Module}.
3442 *
3443 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3444 * factories** are functions which, in turn, are created by a **service provider**.
3445 * The **service providers** are constructor functions. When instantiated they must contain a
3446 * property called `$get`, which holds the **service factory** function.
3447 *
3448 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3449 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3450 * function to get the instance of the **service**.
3451 *
3452 * Often services have no configuration options and there is no need to add methods to the service
3453 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3454 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3455 * services without specifying a provider.
3456 *
3457 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3458 *     {@link auto.$injector $injector}
3459 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3460 *     providers and services.
3461 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3462 *     services, not providers.
3463 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3464 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3465 *     given factory function.
3466 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3467 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3468 *      a new object using the given constructor function.
3469 *
3470 * See the individual methods for more information and examples.
3471 */
3472
3473/**
3474 * @ngdoc method
3475 * @name $provide#provider
3476 * @description
3477 *
3478 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3479 * are constructor functions, whose instances are responsible for "providing" a factory for a
3480 * service.
3481 *
3482 * Service provider names start with the name of the service they provide followed by `Provider`.
3483 * For example, the {@link ng.$log $log} service has a provider called
3484 * {@link ng.$logProvider $logProvider}.
3485 *
3486 * Service provider objects can have additional methods which allow configuration of the provider
3487 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3488 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3489 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3490 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3491 * console or not.
3492 *
3493 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3494                        'Provider'` key.
3495 * @param {(Object|function())} provider If the provider is:
3496 *
3497 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3498 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3499 *   - `Constructor`: a new instance of the provider will be created using
3500 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3501 *
3502 * @returns {Object} registered provider instance
3503
3504 * @example
3505 *
3506 * The following example shows how to create a simple event tracking service and register it using
3507 * {@link auto.$provide#provider $provide.provider()}.
3508 *
3509 * ```js
3510 *  // Define the eventTracker provider
3511 *  function EventTrackerProvider() {
3512 *    var trackingUrl = '/track';
3513 *
3514 *    // A provider method for configuring where the tracked events should been saved
3515 *    this.setTrackingUrl = function(url) {
3516 *      trackingUrl = url;
3517 *    };
3518 *
3519 *    // The service factory function
3520 *    this.$get = ['$http', function($http) {
3521 *      var trackedEvents = {};
3522 *      return {
3523 *        // Call this to track an event
3524 *        event: function(event) {
3525 *          var count = trackedEvents[event] || 0;
3526 *          count += 1;
3527 *          trackedEvents[event] = count;
3528 *          return count;
3529 *        },
3530 *        // Call this to save the tracked events to the trackingUrl
3531 *        save: function() {
3532 *          $http.post(trackingUrl, trackedEvents);
3533 *        }
3534 *      };
3535 *    }];
3536 *  }
3537 *
3538 *  describe('eventTracker', function() {
3539 *    var postSpy;
3540 *
3541 *    beforeEach(module(function($provide) {
3542 *      // Register the eventTracker provider
3543 *      $provide.provider('eventTracker', EventTrackerProvider);
3544 *    }));
3545 *
3546 *    beforeEach(module(function(eventTrackerProvider) {
3547 *      // Configure eventTracker provider
3548 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3549 *    }));
3550 *
3551 *    it('tracks events', inject(function(eventTracker) {
3552 *      expect(eventTracker.event('login')).toEqual(1);
3553 *      expect(eventTracker.event('login')).toEqual(2);
3554 *    }));
3555 *
3556 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3557 *      postSpy = spyOn($http, 'post');
3558 *      eventTracker.event('login');
3559 *      eventTracker.save();
3560 *      expect(postSpy).toHaveBeenCalled();
3561 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3562 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3563 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3564 *    }));
3565 *  });
3566 * ```
3567 */
3568
3569/**
3570 * @ngdoc method
3571 * @name $provide#factory
3572 * @description
3573 *
3574 * Register a **service factory**, which will be called to return the service instance.
3575 * This is short for registering a service where its provider consists of only a `$get` property,
3576 * which is the given service factory function.
3577 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3578 * configure your service in a provider.
3579 *
3580 * @param {string} name The name of the instance.
3581 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3582 *                            for `$provide.provider(name, {$get: $getFn})`.
3583 * @returns {Object} registered provider instance
3584 *
3585 * @example
3586 * Here is an example of registering a service
3587 * ```js
3588 *   $provide.factory('ping', ['$http', function($http) {
3589 *     return function ping() {
3590 *       return $http.send('/ping');
3591 *     };
3592 *   }]);
3593 * ```
3594 * You would then inject and use this service like this:
3595 * ```js
3596 *   someModule.controller('Ctrl', ['ping', function(ping) {
3597 *     ping();
3598 *   }]);
3599 * ```
3600 */
3601
3602
3603/**
3604 * @ngdoc method
3605 * @name $provide#service
3606 * @description
3607 *
3608 * Register a **service constructor**, which will be invoked with `new` to create the service
3609 * instance.
3610 * This is short for registering a service where its provider's `$get` property is the service
3611 * constructor function that will be used to instantiate the service instance.
3612 *
3613 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3614 * as a type/class.
3615 *
3616 * @param {string} name The name of the instance.
3617 * @param {Function} constructor A class (constructor function) that will be instantiated.
3618 * @returns {Object} registered provider instance
3619 *
3620 * @example
3621 * Here is an example of registering a service using
3622 * {@link auto.$provide#service $provide.service(class)}.
3623 * ```js
3624 *   var Ping = function($http) {
3625 *     this.$http = $http;
3626 *   };
3627 *
3628 *   Ping.$inject = ['$http'];
3629 *
3630 *   Ping.prototype.send = function() {
3631 *     return this.$http.get('/ping');
3632 *   };
3633 *   $provide.service('ping', Ping);
3634 * ```
3635 * You would then inject and use this service like this:
3636 * ```js
3637 *   someModule.controller('Ctrl', ['ping', function(ping) {
3638 *     ping.send();
3639 *   }]);
3640 * ```
3641 */
3642
3643
3644/**
3645 * @ngdoc method
3646 * @name $provide#value
3647 * @description
3648 *
3649 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3650 * number, an array, an object or a function.  This is short for registering a service where its
3651 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3652 * service**.
3653 *
3654 * Value services are similar to constant services, except that they cannot be injected into a
3655 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3656 * an Angular
3657 * {@link auto.$provide#decorator decorator}.
3658 *
3659 * @param {string} name The name of the instance.
3660 * @param {*} value The value.
3661 * @returns {Object} registered provider instance
3662 *
3663 * @example
3664 * Here are some examples of creating value services.
3665 * ```js
3666 *   $provide.value('ADMIN_USER', 'admin');
3667 *
3668 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3669 *
3670 *   $provide.value('halfOf', function(value) {
3671 *     return value / 2;
3672 *   });
3673 * ```
3674 */
3675
3676
3677/**
3678 * @ngdoc method
3679 * @name $provide#constant
3680 * @description
3681 *
3682 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3683 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3684 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3685 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3686 *
3687 * @param {string} name The name of the constant.
3688 * @param {*} value The constant value.
3689 * @returns {Object} registered instance
3690 *
3691 * @example
3692 * Here a some examples of creating constants:
3693 * ```js
3694 *   $provide.constant('SHARD_HEIGHT', 306);
3695 *
3696 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3697 *
3698 *   $provide.constant('double', function(value) {
3699 *     return value * 2;
3700 *   });
3701 * ```
3702 */
3703
3704
3705/**
3706 * @ngdoc method
3707 * @name $provide#decorator
3708 * @description
3709 *
3710 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3711 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3712 * service. The object returned by the decorator may be the original service, or a new service
3713 * object which replaces or wraps and delegates to the original service.
3714 *
3715 * @param {string} name The name of the service to decorate.
3716 * @param {function()} decorator This function will be invoked when the service needs to be
3717 *    instantiated and should return the decorated service instance. The function is called using
3718 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3719 *    Local injection arguments:
3720 *
3721 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3722 *      decorated or delegated to.
3723 *
3724 * @example
3725 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3726 * calls to {@link ng.$log#error $log.warn()}.
3727 * ```js
3728 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3729 *     $delegate.warn = $delegate.error;
3730 *     return $delegate;
3731 *   }]);
3732 * ```
3733 */
3734
3735
3736function createInjector(modulesToLoad) {
3737  var INSTANTIATING = {},
3738      providerSuffix = 'Provider',
3739      path = [],
3740      loadedModules = new HashMap([], true),
3741      providerCache = {
3742        $provide: {
3743            provider: supportObject(provider),
3744            factory: supportObject(factory),
3745            service: supportObject(service),
3746            value: supportObject(value),
3747            constant: supportObject(constant),
3748            decorator: decorator
3749          }
3750      },
3751      providerInjector = (providerCache.$injector =
3752          createInternalInjector(providerCache, function() {
3753            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3754          })),
3755      instanceCache = {},
3756      instanceInjector = (instanceCache.$injector =
3757          createInternalInjector(instanceCache, function(servicename) {
3758            var provider = providerInjector.get(servicename + providerSuffix);
3759            return instanceInjector.invoke(provider.$get, provider);
3760          }));
3761
3762
3763  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3764
3765  return instanceInjector;
3766
3767  ////////////////////////////////////
3768  // $provider
3769  ////////////////////////////////////
3770
3771  function supportObject(delegate) {
3772    return function(key, value) {
3773      if (isObject(key)) {
3774        forEach(key, reverseParams(delegate));
3775      } else {
3776        return delegate(key, value);
3777      }
3778    };
3779  }
3780
3781  function provider(name, provider_) {
3782    assertNotHasOwnProperty(name, 'service');
3783    if (isFunction(provider_) || isArray(provider_)) {
3784      provider_ = providerInjector.instantiate(provider_);
3785    }
3786    if (!provider_.$get) {
3787      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3788    }
3789    return providerCache[name + providerSuffix] = provider_;
3790  }
3791
3792  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3793
3794  function service(name, constructor) {
3795    return factory(name, ['$injector', function($injector) {
3796      return $injector.instantiate(constructor);
3797    }]);
3798  }
3799
3800  function value(name, val) { return factory(name, valueFn(val)); }
3801
3802  function constant(name, value) {
3803    assertNotHasOwnProperty(name, 'constant');
3804    providerCache[name] = value;
3805    instanceCache[name] = value;
3806  }
3807
3808  function decorator(serviceName, decorFn) {
3809    var origProvider = providerInjector.get(serviceName + providerSuffix),
3810        orig$get = origProvider.$get;
3811
3812    origProvider.$get = function() {
3813      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3814      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3815    };
3816  }
3817
3818  ////////////////////////////////////
3819  // Module Loading
3820  ////////////////////////////////////
3821  function loadModules(modulesToLoad){
3822    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3823    forEach(modulesToLoad, function(module) {
3824      if (loadedModules.get(module)) return;
3825      loadedModules.put(module, true);
3826
3827      try {
3828        if (isString(module)) {
3829          moduleFn = angularModule(module);
3830          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3831
3832          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3833            var invokeArgs = invokeQueue[i],
3834                provider = providerInjector.get(invokeArgs[0]);
3835
3836            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3837          }
3838        } else if (isFunction(module)) {
3839            runBlocks.push(providerInjector.invoke(module));
3840        } else if (isArray(module)) {
3841            runBlocks.push(providerInjector.invoke(module));
3842        } else {
3843          assertArgFn(module, 'module');
3844        }
3845      } catch (e) {
3846        if (isArray(module)) {
3847          module = module[module.length - 1];
3848        }
3849        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3850          // Safari & FF's stack traces don't contain error.message content
3851          // unlike those of Chrome and IE
3852          // So if stack doesn't contain message, we create a new string that contains both.
3853          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3854          /* jshint -W022 */
3855          e = e.message + '\n' + e.stack;
3856        }
3857        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3858                  module, e.stack || e.message || e);
3859      }
3860    });
3861    return runBlocks;
3862  }
3863
3864  ////////////////////////////////////
3865  // internal Injector
3866  ////////////////////////////////////
3867
3868  function createInternalInjector(cache, factory) {
3869
3870    function getService(serviceName) {
3871      if (cache.hasOwnProperty(serviceName)) {
3872        if (cache[serviceName] === INSTANTIATING) {
3873          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
3874                    serviceName + ' <- ' + path.join(' <- '));
3875        }
3876        return cache[serviceName];
3877      } else {
3878        try {
3879          path.unshift(serviceName);
3880          cache[serviceName] = INSTANTIATING;
3881          return cache[serviceName] = factory(serviceName);
3882        } catch (err) {
3883          if (cache[serviceName] === INSTANTIATING) {
3884            delete cache[serviceName];
3885          }
3886          throw err;
3887        } finally {
3888          path.shift();
3889        }
3890      }
3891    }
3892
3893    function invoke(fn, self, locals){
3894      var args = [],
3895          $inject = annotate(fn),
3896          length, i,
3897          key;
3898
3899      for(i = 0, length = $inject.length; i < length; i++) {
3900        key = $inject[i];
3901        if (typeof key !== 'string') {
3902          throw $injectorMinErr('itkn',
3903                  'Incorrect injection token! Expected service name as string, got {0}', key);
3904        }
3905        args.push(
3906          locals && locals.hasOwnProperty(key)
3907          ? locals[key]
3908          : getService(key)
3909        );
3910      }
3911      if (isArray(fn)) {
3912        fn = fn[length];
3913      }
3914
3915      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3916      // #5388
3917      return fn.apply(self, args);
3918    }
3919
3920    function instantiate(Type, locals) {
3921      var Constructor = function() {},
3922          instance, returnedValue;
3923
3924      // Check if Type is annotated and use just the given function at n-1 as parameter
3925      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3926      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3927      instance = new Constructor();
3928      returnedValue = invoke(Type, instance, locals);
3929
3930      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3931    }
3932
3933    return {
3934      invoke: invoke,
3935      instantiate: instantiate,
3936      get: getService,
3937      annotate: annotate,
3938      has: function(name) {
3939        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3940      }
3941    };
3942  }
3943}
3944
3945/**
3946 * @ngdoc service
3947 * @name $anchorScroll
3948 * @kind function
3949 * @requires $window
3950 * @requires $location
3951 * @requires $rootScope
3952 *
3953 * @description
3954 * When called, it checks current value of `$location.hash()` and scrolls to the related element,
3955 * according to rules specified in
3956 * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
3957 *
3958 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3959 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3960 *
3961 * @example
3962   <example>
3963     <file name="index.html">
3964       <div id="scrollArea" ng-controller="ScrollCtrl">
3965         <a ng-click="gotoBottom()">Go to bottom</a>
3966         <a id="bottom"></a> You're at the bottom!
3967       </div>
3968     </file>
3969     <file name="script.js">
3970       function ScrollCtrl($scope, $location, $anchorScroll) {
3971         $scope.gotoBottom = function (){
3972           // set the location.hash to the id of
3973           // the element you wish to scroll to.
3974           $location.hash('bottom');
3975
3976           // call $anchorScroll()
3977           $anchorScroll();
3978         };
3979       }
3980     </file>
3981     <file name="style.css">
3982       #scrollArea {
3983         height: 350px;
3984         overflow: auto;
3985       }
3986
3987       #bottom {
3988         display: block;
3989         margin-top: 2000px;
3990       }
3991     </file>
3992   </example>
3993 */
3994function $AnchorScrollProvider() {
3995
3996  var autoScrollingEnabled = true;
3997
3998  this.disableAutoScrolling = function() {
3999    autoScrollingEnabled = false;
4000  };
4001
4002  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4003    var document = $window.document;
4004
4005    // helper function to get first anchor from a NodeList
4006    // can't use filter.filter, as it accepts only instances of Array
4007    // and IE can't convert NodeList to an array using [].slice
4008    // TODO(vojta): use filter if we change it to accept lists as well
4009    function getFirstAnchor(list) {
4010      var result = null;
4011      forEach(list, function(element) {
4012        if (!result && lowercase(element.nodeName) === 'a') result = element;
4013      });
4014      return result;
4015    }
4016
4017    function scroll() {
4018      var hash = $location.hash(), elm;
4019
4020      // empty hash, scroll to the top of the page
4021      if (!hash) $window.scrollTo(0, 0);
4022
4023      // element with given id
4024      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4025
4026      // first anchor with given name :-D
4027      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4028
4029      // no element and hash == 'top', scroll to the top of the page
4030      else if (hash === 'top') $window.scrollTo(0, 0);
4031    }
4032
4033    // does not scroll when user clicks on anchor link that is currently on
4034    // (no url change, no $location.hash() change), browser native does scroll
4035    if (autoScrollingEnabled) {
4036      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4037        function autoScrollWatchAction() {
4038          $rootScope.$evalAsync(scroll);
4039        });
4040    }
4041
4042    return scroll;
4043  }];
4044}
4045
4046var $animateMinErr = minErr('$animate');
4047
4048/**
4049 * @ngdoc provider
4050 * @name $animateProvider
4051 *
4052 * @description
4053 * Default implementation of $animate that doesn't perform any animations, instead just
4054 * synchronously performs DOM
4055 * updates and calls done() callbacks.
4056 *
4057 * In order to enable animations the ngAnimate module has to be loaded.
4058 *
4059 * To see the functional implementation check out src/ngAnimate/animate.js
4060 */
4061var $AnimateProvider = ['$provide', function($provide) {
4062
4063
4064  this.$$selectors = {};
4065
4066
4067  /**
4068   * @ngdoc method
4069   * @name $animateProvider#register
4070   *
4071   * @description
4072   * Registers a new injectable animation factory function. The factory function produces the
4073   * animation object which contains callback functions for each event that is expected to be
4074   * animated.
4075   *
4076   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4077   *   must be called once the element animation is complete. If a function is returned then the
4078   *   animation service will use this function to cancel the animation whenever a cancel event is
4079   *   triggered.
4080   *
4081   *
4082   * ```js
4083   *   return {
4084     *     eventFn : function(element, done) {
4085     *       //code to run the animation
4086     *       //once complete, then run done()
4087     *       return function cancellationFunction() {
4088     *         //code to cancel the animation
4089     *       }
4090     *     }
4091     *   }
4092   * ```
4093   *
4094   * @param {string} name The name of the animation.
4095   * @param {Function} factory The factory function that will be executed to return the animation
4096   *                           object.
4097   */
4098  this.register = function(name, factory) {
4099    var key = name + '-animation';
4100    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4101        "Expecting class selector starting with '.' got '{0}'.", name);
4102    this.$$selectors[name.substr(1)] = key;
4103    $provide.factory(key, factory);
4104  };
4105
4106  /**
4107   * @ngdoc method
4108   * @name $animateProvider#classNameFilter
4109   *
4110   * @description
4111   * Sets and/or returns the CSS class regular expression that is checked when performing
4112   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4113   * therefore enable $animate to attempt to perform an animation on any element.
4114   * When setting the classNameFilter value, animations will only be performed on elements
4115   * that successfully match the filter expression. This in turn can boost performance
4116   * for low-powered devices as well as applications containing a lot of structural operations.
4117   * @param {RegExp=} expression The className expression which will be checked against all animations
4118   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4119   */
4120  this.classNameFilter = function(expression) {
4121    if(arguments.length === 1) {
4122      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4123    }
4124    return this.$$classNameFilter;
4125  };
4126
4127  this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
4128
4129    function async(fn) {
4130      fn && $$asyncCallback(fn);
4131    }
4132
4133    /**
4134     *
4135     * @ngdoc service
4136     * @name $animate
4137     * @description The $animate service provides rudimentary DOM manipulation functions to
4138     * insert, remove and move elements within the DOM, as well as adding and removing classes.
4139     * This service is the core service used by the ngAnimate $animator service which provides
4140     * high-level animation hooks for CSS and JavaScript.
4141     *
4142     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4143     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4144     * manipulation operations.
4145     *
4146     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4147     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4148     * page}.
4149     */
4150    return {
4151
4152      /**
4153       *
4154       * @ngdoc method
4155       * @name $animate#enter
4156       * @kind function
4157       * @description Inserts the element into the DOM either after the `after` element or within
4158       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4159       * @param {DOMElement} element the element which will be inserted into the DOM
4160       * @param {DOMElement} parent the parent element which will append the element as
4161       *   a child (if the after element is not present)
4162       * @param {DOMElement} after the sibling element which will append the element
4163       *   after itself
4164       * @param {Function=} done callback function that will be called after the element has been
4165       *   inserted into the DOM
4166       */
4167      enter : function(element, parent, after, done) {
4168        if (after) {
4169          after.after(element);
4170        } else {
4171          if (!parent || !parent[0]) {
4172            parent = after.parent();
4173          }
4174          parent.append(element);
4175        }
4176        async(done);
4177      },
4178
4179      /**
4180       *
4181       * @ngdoc method
4182       * @name $animate#leave
4183       * @kind function
4184       * @description Removes the element from the DOM. Once complete, the done() callback will be
4185       *   fired (if provided).
4186       * @param {DOMElement} element the element which will be removed from the DOM
4187       * @param {Function=} done callback function that will be called after the element has been
4188       *   removed from the DOM
4189       */
4190      leave : function(element, done) {
4191        element.remove();
4192        async(done);
4193      },
4194
4195      /**
4196       *
4197       * @ngdoc method
4198       * @name $animate#move
4199       * @kind function
4200       * @description Moves the position of the provided element within the DOM to be placed
4201       * either after the `after` element or inside of the `parent` element. Once complete, the
4202       * done() callback will be fired (if provided).
4203       *
4204       * @param {DOMElement} element the element which will be moved around within the
4205       *   DOM
4206       * @param {DOMElement} parent the parent element where the element will be
4207       *   inserted into (if the after element is not present)
4208       * @param {DOMElement} after the sibling element where the element will be
4209       *   positioned next to
4210       * @param {Function=} done the callback function (if provided) that will be fired after the
4211       *   element has been moved to its new position
4212       */
4213      move : function(element, parent, after, done) {
4214        // Do not remove element before insert. Removing will cause data associated with the
4215        // element to be dropped. Insert will implicitly do the remove.
4216        this.enter(element, parent, after, done);
4217      },
4218
4219      /**
4220       *
4221       * @ngdoc method
4222       * @name $animate#addClass
4223       * @kind function
4224       * @description Adds the provided className CSS class value to the provided element. Once
4225       * complete, the done() callback will be fired (if provided).
4226       * @param {DOMElement} element the element which will have the className value
4227       *   added to it
4228       * @param {string} className the CSS class which will be added to the element
4229       * @param {Function=} done the callback function (if provided) that will be fired after the
4230       *   className value has been added to the element
4231       */
4232      addClass : function(element, className, done) {
4233        className = isString(className) ?
4234                      className :
4235                      isArray(className) ? className.join(' ') : '';
4236        forEach(element, function (element) {
4237          jqLiteAddClass(element, className);
4238        });
4239        async(done);
4240      },
4241
4242      /**
4243       *
4244       * @ngdoc method
4245       * @name $animate#removeClass
4246       * @kind function
4247       * @description Removes the provided className CSS class value from the provided element.
4248       * Once complete, the done() callback will be fired (if provided).
4249       * @param {DOMElement} element the element which will have the className value
4250       *   removed from it
4251       * @param {string} className the CSS class which will be removed from the element
4252       * @param {Function=} done the callback function (if provided) that will be fired after the
4253       *   className value has been removed from the element
4254       */
4255      removeClass : function(element, className, done) {
4256        className = isString(className) ?
4257                      className :
4258                      isArray(className) ? className.join(' ') : '';
4259        forEach(element, function (element) {
4260          jqLiteRemoveClass(element, className);
4261        });
4262        async(done);
4263      },
4264
4265      /**
4266       *
4267       * @ngdoc method
4268       * @name $animate#setClass
4269       * @kind function
4270       * @description Adds and/or removes the given CSS classes to and from the element.
4271       * Once complete, the done() callback will be fired (if provided).
4272       * @param {DOMElement} element the element which will have its CSS classes changed
4273       *   removed from it
4274       * @param {string} add the CSS classes which will be added to the element
4275       * @param {string} remove the CSS class which will be removed from the element
4276       * @param {Function=} done the callback function (if provided) that will be fired after the
4277       *   CSS classes have been set on the element
4278       */
4279      setClass : function(element, add, remove, done) {
4280        forEach(element, function (element) {
4281          jqLiteAddClass(element, add);
4282          jqLiteRemoveClass(element, remove);
4283        });
4284        async(done);
4285      },
4286
4287      enabled : noop
4288    };
4289  }];
4290}];
4291
4292function $$AsyncCallbackProvider(){
4293  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4294    return $$rAF.supported
4295      ? function(fn) { return $$rAF(fn); }
4296      : function(fn) {
4297        return $timeout(fn, 0, false);
4298      };
4299  }];
4300}
4301
4302/**
4303 * ! This is a private undocumented service !
4304 *
4305 * @name $browser
4306 * @requires $log
4307 * @description
4308 * This object has two goals:
4309 *
4310 * - hide all the global state in the browser caused by the window object
4311 * - abstract away all the browser specific features and inconsistencies
4312 *
4313 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4314 * service, which can be used for convenient testing of the application without the interaction with
4315 * the real browser apis.
4316 */
4317/**
4318 * @param {object} window The global window object.
4319 * @param {object} document jQuery wrapped document.
4320 * @param {function()} XHR XMLHttpRequest constructor.
4321 * @param {object} $log console.log or an object with the same interface.
4322 * @param {object} $sniffer $sniffer service
4323 */
4324function Browser(window, document, $log, $sniffer) {
4325  var self = this,
4326      rawDocument = document[0],
4327      location = window.location,
4328      history = window.history,
4329      setTimeout = window.setTimeout,
4330      clearTimeout = window.clearTimeout,
4331      pendingDeferIds = {};
4332
4333  self.isMock = false;
4334
4335  var outstandingRequestCount = 0;
4336  var outstandingRequestCallbacks = [];
4337
4338  // TODO(vojta): remove this temporary api
4339  self.$$completeOutstandingRequest = completeOutstandingRequest;
4340  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4341
4342  /**
4343   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4344   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4345   */
4346  function completeOutstandingRequest(fn) {
4347    try {
4348      fn.apply(null, sliceArgs(arguments, 1));
4349    } finally {
4350      outstandingRequestCount--;
4351      if (outstandingRequestCount === 0) {
4352        while(outstandingRequestCallbacks.length) {
4353          try {
4354            outstandingRequestCallbacks.pop()();
4355          } catch (e) {
4356            $log.error(e);
4357          }
4358        }
4359      }
4360    }
4361  }
4362
4363  /**
4364   * @private
4365   * Note: this method is used only by scenario runner
4366   * TODO(vojta): prefix this method with $$ ?
4367   * @param {function()} callback Function that will be called when no outstanding request
4368   */
4369  self.notifyWhenNoOutstandingRequests = function(callback) {
4370    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4371    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4372    // regular poller would result in flaky tests.
4373    forEach(pollFns, function(pollFn){ pollFn(); });
4374
4375    if (outstandingRequestCount === 0) {
4376      callback();
4377    } else {
4378      outstandingRequestCallbacks.push(callback);
4379    }
4380  };
4381
4382  //////////////////////////////////////////////////////////////
4383  // Poll Watcher API
4384  //////////////////////////////////////////////////////////////
4385  var pollFns = [],
4386      pollTimeout;
4387
4388  /**
4389   * @name $browser#addPollFn
4390   *
4391   * @param {function()} fn Poll function to add
4392   *
4393   * @description
4394   * Adds a function to the list of functions that poller periodically executes,
4395   * and starts polling if not started yet.
4396   *
4397   * @returns {function()} the added function
4398   */
4399  self.addPollFn = function(fn) {
4400    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4401    pollFns.push(fn);
4402    return fn;
4403  };
4404
4405  /**
4406   * @param {number} interval How often should browser call poll functions (ms)
4407   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4408   *
4409   * @description
4410   * Configures the poller to run in the specified intervals, using the specified
4411   * setTimeout fn and kicks it off.
4412   */
4413  function startPoller(interval, setTimeout) {
4414    (function check() {
4415      forEach(pollFns, function(pollFn){ pollFn(); });
4416      pollTimeout = setTimeout(check, interval);
4417    })();
4418  }
4419
4420  //////////////////////////////////////////////////////////////
4421  // URL API
4422  //////////////////////////////////////////////////////////////
4423
4424  var lastBrowserUrl = location.href,
4425      baseElement = document.find('base'),
4426      newLocation = null;
4427
4428  /**
4429   * @name $browser#url
4430   *
4431   * @description
4432   * GETTER:
4433   * Without any argument, this method just returns current value of location.href.
4434   *
4435   * SETTER:
4436   * With at least one argument, this method sets url to new value.
4437   * If html5 history api supported, pushState/replaceState is used, otherwise
4438   * location.href/location.replace is used.
4439   * Returns its own instance to allow chaining
4440   *
4441   * NOTE: this api is intended for use only by the $location service. Please use the
4442   * {@link ng.$location $location service} to change url.
4443   *
4444   * @param {string} url New url (when used as setter)
4445   * @param {boolean=} replace Should new url replace current history record ?
4446   */
4447  self.url = function(url, replace) {
4448    // Android Browser BFCache causes location, history reference to become stale.
4449    if (location !== window.location) location = window.location;
4450    if (history !== window.history) history = window.history;
4451
4452    // setter
4453    if (url) {
4454      if (lastBrowserUrl == url) return;
4455      lastBrowserUrl = url;
4456      if ($sniffer.history) {
4457        if (replace) history.replaceState(null, '', url);
4458        else {
4459          history.pushState(null, '', url);
4460          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4461          baseElement.attr('href', baseElement.attr('href'));
4462        }
4463      } else {
4464        newLocation = url;
4465        if (replace) {
4466          location.replace(url);
4467        } else {
4468          location.href = url;
4469        }
4470      }
4471      return self;
4472    // getter
4473    } else {
4474      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4475      //   methods not updating location.href synchronously.
4476      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4477      return newLocation || location.href.replace(/%27/g,"'");
4478    }
4479  };
4480
4481  var urlChangeListeners = [],
4482      urlChangeInit = false;
4483
4484  function fireUrlChange() {
4485    newLocation = null;
4486    if (lastBrowserUrl == self.url()) return;
4487
4488    lastBrowserUrl = self.url();
4489    forEach(urlChangeListeners, function(listener) {
4490      listener(self.url());
4491    });
4492  }
4493
4494  /**
4495   * @name $browser#onUrlChange
4496   *
4497   * @description
4498   * Register callback function that will be called, when url changes.
4499   *
4500   * It's only called when the url is changed from outside of angular:
4501   * - user types different url into address bar
4502   * - user clicks on history (forward/back) button
4503   * - user clicks on a link
4504   *
4505   * It's not called when url is changed by $browser.url() method
4506   *
4507   * The listener gets called with new url as parameter.
4508   *
4509   * NOTE: this api is intended for use only by the $location service. Please use the
4510   * {@link ng.$location $location service} to monitor url changes in angular apps.
4511   *
4512   * @param {function(string)} listener Listener function to be called when url changes.
4513   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4514   */
4515  self.onUrlChange = function(callback) {
4516    // TODO(vojta): refactor to use node's syntax for events
4517    if (!urlChangeInit) {
4518      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4519      // don't fire popstate when user change the address bar and don't fire hashchange when url
4520      // changed by push/replaceState
4521
4522      // html5 history api - popstate event
4523      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4524      // hashchange event
4525      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4526      // polling
4527      else self.addPollFn(fireUrlChange);
4528
4529      urlChangeInit = true;
4530    }
4531
4532    urlChangeListeners.push(callback);
4533    return callback;
4534  };
4535
4536  //////////////////////////////////////////////////////////////
4537  // Misc API
4538  //////////////////////////////////////////////////////////////
4539
4540  /**
4541   * @name $browser#baseHref
4542   *
4543   * @description
4544   * Returns current <base href>
4545   * (always relative - without domain)
4546   *
4547   * @returns {string} The current base href
4548   */
4549  self.baseHref = function() {
4550    var href = baseElement.attr('href');
4551    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4552  };
4553
4554  //////////////////////////////////////////////////////////////
4555  // Cookies API
4556  //////////////////////////////////////////////////////////////
4557  var lastCookies = {};
4558  var lastCookieString = '';
4559  var cookiePath = self.baseHref();
4560
4561  /**
4562   * @name $browser#cookies
4563   *
4564   * @param {string=} name Cookie name
4565   * @param {string=} value Cookie value
4566   *
4567   * @description
4568   * The cookies method provides a 'private' low level access to browser cookies.
4569   * It is not meant to be used directly, use the $cookie service instead.
4570   *
4571   * The return values vary depending on the arguments that the method was called with as follows:
4572   *
4573   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4574   *   it
4575   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4576   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4577   *   way)
4578   *
4579   * @returns {Object} Hash of all cookies (if called without any parameter)
4580   */
4581  self.cookies = function(name, value) {
4582    /* global escape: false, unescape: false */
4583    var cookieLength, cookieArray, cookie, i, index;
4584
4585    if (name) {
4586      if (value === undefined) {
4587        rawDocument.cookie = escape(name) + "=;
4587path=" + cookiePath +
4588                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4589      } else {
4590        if (isString(value)) {
4591          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4592                                ';path=' + cookiePath).length + 1;
4593
4594          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4595          // - 300 cookies
4596          // - 20 cookies per unique domain
4597          // - 4096 bytes per cookie
4598          if (cookieLength > 4096) {
4599            $log.warn("Cookie '"+ name +
4600              "' possibly not set or overflowed because it was too large ("+
4601              cookieLength + " > 4096 bytes)!");
4602          }
4603        }
4604      }
4605    } else {
4606      if (rawDocument.cookie !== lastCookieString) {
4607        lastCookieString = rawDocument.cookie;
4608        cookieArray = lastCookieString.split("; ");
4609        lastCookies = {};
4610
4611        for (i = 0; i < cookieArray.length; i++) {
4612          cookie = cookieArray[i];
4613          index = cookie.indexOf('=');
4614          if (index > 0) { //ignore nameless cookies
4615            name = unescape(cookie.substring(0, index));
4616            // the first value that is seen for a cookie is the most
4617            // specific one.  values for the same cookie name that
4618            // follow are for less specific paths.
4619            if (lastCookies[name] === undefined) {
4620              lastCookies[name] = unescape(cookie.substring(index + 1));
4621            }
4622          }
4623        }
4624      }
4625      return lastCookies;
4626    }
4627  };
4628
4629
4630  /**
4631   * @name $browser#defer
4632   * @param {function()} fn A function, who's execution should be deferred.
4633   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4634   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4635   *
4636   * @description
4637   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4638   *
4639   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4640   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4641   * via `$browser.defer.flush()`.
4642   *
4643   */
4644  self.defer = function(fn, delay) {
4645    var timeoutId;
4646    outstandingRequestCount++;
4647    timeoutId = setTimeout(function() {
4648      delete pendingDeferIds[timeoutId];
4649      completeOutstandingRequest(fn);
4650    }, delay || 0);
4651    pendingDeferIds[timeoutId] = true;
4652    return timeoutId;
4653  };
4654
4655
4656  /**
4657   * @name $browser#defer.cancel
4658   *
4659   * @description
4660   * Cancels a deferred task identified with `deferId`.
4661   *
4662   * @param {*} deferId Token returned by the `$browser.defer` function.
4663   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4664   *                    canceled.
4665   */
4666  self.defer.cancel = function(deferId) {
4667    if (pendingDeferIds[deferId]) {
4668      delete pendingDeferIds[deferId];
4669      clearTimeout(deferId);
4670      completeOutstandingRequest(noop);
4671      return true;
4672    }
4673    return false;
4674  };
4675
4676}
4677
4678function $BrowserProvider(){
4679  this.$get = ['$window', '$log', '$sniffer', '$document',
4680      function( $window,   $log,   $sniffer,   $document){
4681        return new Browser($window, $document, $log, $sniffer);
4682      }];
4683}
4684
4685/**
4686 * @ngdoc service
4687 * @name $cacheFactory
4688 *
4689 * @description
4690 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4691 * them.
4692 *
4693 * ```js
4694 *
4695 *  var cache = $cacheFactory('cacheId');
4696 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4697 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4698 *
4699 *  cache.put("key", "value");
4700 *  cache.put("another key", "another value");
4701 *
4702 *  // We've specified no options on creation
4703 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4704 *
4705 * ```
4706 *
4707 *
4708 * @param {string} cacheId Name or id of the newly created cache.
4709 * @param {object=} options Options object that specifies the cache behavior. Properties:
4710 *
4711 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4712 *
4713 * @returns {object} Newly created cache object with the following set of methods:
4714 *
4715 * - `{object}` `info()` — Returns id, size, and options of cache.
4716 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4717 *   it.
4718 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4719 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4720 * - `{void}` `removeAll()` — Removes all cached values.
4721 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4722 *
4723 * @example
4724   <example module="cacheExampleApp">
4725     <file name="index.html">
4726       <div ng-controller="CacheController">
4727         <input ng-model="newCacheKey" placeholder="Key">
4728         <input ng-model="newCacheValue" placeholder="Value">
4729         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4730
4731         <p ng-if="keys.length">Cached Values</p>
4732         <div ng-repeat="key in keys">
4733           <span ng-bind="key"></span>
4734           <span>: </span>
4735           <b ng-bind="cache.get(key)"></b>
4736         </div>
4737
4738         <p>Cache Info</p>
4739         <div ng-repeat="(key, value) in cache.info()">
4740           <span ng-bind="key"></span>
4741           <span>: </span>
4742           <b ng-bind="value"></b>
4743         </div>
4744       </div>
4745     </file>
4746     <file name="script.js">
4747       angular.module('cacheExampleApp', []).
4748         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4749           $scope.keys = [];
4750           $scope.cache = $cacheFactory('cacheId');
4751           $scope.put = function(key, value) {
4752             $scope.cache.put(key, value);
4753             $scope.keys.push(key);
4754           };
4755         }]);
4756     </file>
4757     <file name="style.css">
4758       p {
4759         margin: 10px 0 3px;
4760       }
4761     </file>
4762   </example>
4763 */
4764function $CacheFactoryProvider() {
4765
4766  this.$get = function() {
4767    var caches = {};
4768
4769    function cacheFactory(cacheId, options) {
4770      if (cacheId in caches) {
4771        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4772      }
4773
4774      var size = 0,
4775          stats = extend({}, options, {id: cacheId}),
4776          data = {},
4777          capacity = (options && options.capacity) || Number.MAX_VALUE,
4778          lruHash = {},
4779          freshEnd = null,
4780          staleEnd = null;
4781
4782      /**
4783       * @ngdoc type
4784       * @name $cacheFactory.Cache
4785       *
4786       * @description
4787       * A cache object used to store and retrieve data, primarily used by
4788       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4789       * templates and other data.
4790       *
4791       * ```js
4792       *  angular.module('superCache')
4793       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4794       *      return $cacheFactory('super-cache');
4795       *    }]);
4796       * ```
4797       *
4798       * Example test:
4799       *
4800       * ```js
4801       *  it('should behave like a cache', inject(function(superCache) {
4802       *    superCache.put('key', 'value');
4803       *    superCache.put('another key', 'another value');
4804       *
4805       *    expect(superCache.info()).toEqual({
4806       *      id: 'super-cache',
4807       *      size: 2
4808       *    });
4809       *
4810       *    superCache.remove('another key');
4811       *    expect(superCache.get('another key')).toBeUndefined();
4812       *
4813       *    superCache.removeAll();
4814       *    expect(superCache.info()).toEqual({
4815       *      id: 'super-cache',
4816       *      size: 0
4817       *    });
4818       *  }));
4819       * ```
4820       */
4821      return caches[cacheId] = {
4822
4823        /**
4824         * @ngdoc method
4825         * @name $cacheFactory.Cache#put
4826         * @kind function
4827         *
4828         * @description
4829         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4830         * retrieved later, and incrementing the size of the cache if the key was not already
4831         * present in the cache. If behaving like an LRU cache, it will also remove stale
4832         * entries from the set.
4833         *
4834         * It will not insert undefined values into the cache.
4835         *
4836         * @param {string} key the key under which the cached data is stored.
4837         * @param {*} value the value to store alongside the key. If it is undefined, the key
4838         *    will not be stored.
4839         * @returns {*} the value stored.
4840         */
4841        put: function(key, value) {
4842          if (capacity < Number.MAX_VALUE) {
4843            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4844
4845            refresh(lruEntry);
4846          }
4847
4848          if (isUndefined(value)) return;
4849          if (!(key in data)) size++;
4850          data[key] = value;
4851
4852          if (size > capacity) {
4853            this.remove(staleEnd.key);
4854          }
4855
4856          return value;
4857        },
4858
4859        /**
4860         * @ngdoc method
4861         * @name $cacheFactory.Cache#get
4862         * @kind function
4863         *
4864         * @description
4865         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4866         *
4867         * @param {string} key the key of the data to be retrieved
4868         * @returns {*} the value stored.
4869         */
4870        get: function(key) {
4871          if (capacity < Number.MAX_VALUE) {
4872            var lruEntry = lruHash[key];
4873
4874            if (!lruEntry) return;
4875
4876            refresh(lruEntry);
4877          }
4878
4879          return data[key];
4880        },
4881
4882
4883        /**
4884         * @ngdoc method
4885         * @name $cacheFactory.Cache#remove
4886         * @kind function
4887         *
4888         * @description
4889         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4890         *
4891         * @param {string} key the key of the entry to be removed
4892         */
4893        remove: function(key) {
4894          if (capacity < Number.MAX_VALUE) {
4895            var lruEntry = lruHash[key];
4896
4897            if (!lruEntry) return;
4898
4899            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4900            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4901            link(lruEntry.n,lruEntry.p);
4902
4903            delete lruHash[key];
4904          }
4905
4906          delete data[key];
4907          size--;
4908        },
4909
4910
4911        /**
4912         * @ngdoc method
4913         * @name $cacheFactory.Cache#removeAll
4914         * @kind function
4915         *
4916         * @description
4917         * Clears the cache object of any entries.
4918         */
4919        removeAll: function() {
4920          data = {};
4921          size = 0;
4922          lruHash = {};
4923          freshEnd = staleEnd = null;
4924        },
4925
4926
4927        /**
4928         * @ngdoc method
4929         * @name $cacheFactory.Cache#destroy
4930         * @kind function
4931         *
4932         * @description
4933         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
4934         * removing it from the {@link $cacheFactory $cacheFactory} set.
4935         */
4936        destroy: function() {
4937          data = null;
4938          stats = null;
4939          lruHash = null;
4940          delete caches[cacheId];
4941        },
4942
4943
4944        /**
4945         * @ngdoc method
4946         * @name $cacheFactory.Cache#info
4947         * @kind function
4948         *
4949         * @description
4950         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
4951         *
4952         * @returns {object} an object with the following properties:
4953         *   <ul>
4954         *     <li>**id**: the id of the cache instance</li>
4955         *     <li>**size**: the number of entries kept in the cache instance</li>
4956         *     <li>**...**: any additional properties from the options object when creating the
4957         *       cache.</li>
4958         *   </ul>
4959         */
4960        info: function() {
4961          return extend({}, stats, {size: size});
4962        }
4963      };
4964
4965
4966      /**
4967       * makes the `entry` the freshEnd of the LRU linked list
4968       */
4969      function refresh(entry) {
4970        if (entry != freshEnd) {
4971          if (!staleEnd) {
4972            staleEnd = entry;
4973          } else if (staleEnd == entry) {
4974            staleEnd = entry.n;
vendor: 4,905 bytes, lines 4975-5138
4975          }
4976
4977          link(entry.n, entry.p);
4978          link(entry, freshEnd);
4979          freshEnd = entry;
4980          freshEnd.n = null;
4981        }
4982      }
4983
4984
4985      /**
4986       * bidirectionally links two entries of the LRU linked list
4987       */
4988      function link(nextEntry, prevEntry) {
4989        if (nextEntry != prevEntry) {
4990          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
4991          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
4992        }
4993      }
4994    }
4995
4996
4997  /**
4998   * @ngdoc method
4999   * @name $cacheFactory#info
5000   *
5001   * @description
5002   * Get information about all the caches that have been created
5003   *
5004   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5005   */
5006    cacheFactory.info = function() {
5007      var info = {};
5008      forEach(caches, function(cache, cacheId) {
5009        info[cacheId] = cache.info();
5010      });
5011      return info;
5012    };
5013
5014
5015  /**
5016   * @ngdoc method
5017   * @name $cacheFactory#get
5018   *
5019   * @description
5020   * Get access to a cache object by the `cacheId` used when it was created.
5021   *
5022   * @param {string} cacheId Name or id of a cache to access.
5023   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5024   */
5025    cacheFactory.get = function(cacheId) {
5026      return caches[cacheId];
5027    };
5028
5029
5030    return cacheFactory;
5031  };
5032}
5033
5034/**
5035 * @ngdoc service
5036 * @name $templateCache
5037 *
5038 * @description
5039 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5040 * can load templates directly into the cache in a `script` tag, or by consuming the
5041 * `$templateCache` service directly.
5042 *
5043 * Adding via the `script` tag:
5044 *
5045 * ```html
5046 *   <script type="text/ng-template" id="templateId.html">
5047 *     <p>This is the content of the template</p>
5048 *   </script>
5049 * ```
5050 *
5051 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5052 * the document, but it must be below the `ng-app` definition.
5053 *
5054 * Adding via the $templateCache service:
5055 *
5056 * ```js
5057 * var myApp = angular.module('myApp', []);
5058 * myApp.run(function($templateCache) {
5059 *   $templateCache.put('templateId.html', 'This is the content of the template');
5060 * });
5061 * ```
5062 *
5063 * To retrieve the template later, simply use it in your HTML:
5064 * ```html
5065 * <div ng-include=" 'templateId.html' "></div>
5066 * ```
5067 *
5068 * or get it via Javascript:
5069 * ```js
5070 * $templateCache.get('templateId.html')
5071 * ```
5072 *
5073 * See {@link ng.$cacheFactory $cacheFactory}.
5074 *
5075 */
5076function $TemplateCacheProvider() {
5077  this.$get = ['$cacheFactory', function($cacheFactory) {
5078    return $cacheFactory('templates');
5079  }];
5080}
5081
5082/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5083 *
5084 * DOM-related variables:
5085 *
5086 * - "node" - DOM Node
5087 * - "element" - DOM Element or Node
5088 * - "$node" or "$element" - jqLite-wrapped node or element
5089 *
5090 *
5091 * Compiler related stuff:
5092 *
5093 * - "linkFn" - linking fn of a single directive
5094 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5095 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5096 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5097 */
5098
5099
5100/**
5101 * @ngdoc service
5102 * @name $compile
5103 * @kind function
5104 *
5105 * @description
5106 * Compiles an HTML string or DOM into a template and produces a template function, which
5107 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5108 *
5109 * The compilation is a process of walking the DOM tree and matching DOM elements to
5110 * {@link ng.$compileProvider#directive directives}.
5111 *
5112 * <div class="alert alert-warning">
5113 * **Note:** This document is an in-depth reference of all directive options.
5114 * For a gentle introduction to directives with examples of common use cases,
5115 * see the {@link guide/directive directive guide}.
5116 * </div>
5117 *
5118 * ## Comprehensive Directive API
5119 *
5120 * There are many different options for a directive.
5121 *
5122 * The difference resides in the return value of the factory function.
5123 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5124 * or just the `postLink` function (all other properties will have the default values).
5125 *
5126 * <div class="alert alert-success">
5127 * **Best Practice:** It's recommended to use the "directive definition object" form.
5128 * </div>
5129 *
5130 * Here's an example directive declared with a Directive Definition Object:
5131 *
5132 * ```js
5133 *   var myModule = angular.module(...);
5134 *
5135 *   myModule.directive('directiveName', function factory(injectables) {
5136 *     var directiveDefinitionObject = {
5137 *       priority: 0,
5138 *       template: '<div></div>
5138', // or // function(tElement, tAttrs) { ... },
5139 *       // or
5140 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5141 *       transclude: false,
5142 *       restrict: 'A',
5143 *       scope: false,
5144 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5145 *       controllerAs: 'stringAlias',
5146 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5147 *       compile: function compile(tElement, tAttrs, transclude) {
5148 *         return {
5149 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5150 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5151 *         }
5152 *         // or
5153 *         // return function postLink( ... ) { ... }
5154 *       },
5155 *       // or
5156 *       // link: {
5157 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5158 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5159 *       // }
5160 *       // or
5161 *       // link: function postLink( ... ) { ... }
5162 *     };
5163 *     return directiveDefinitionObject;
5164 *   });
5165 * ```
5166 *
5167 * <div class="alert alert-warning">
5168 * **Note:** Any unspecified options will use the default value. You can see the default values below.
5169 * </div>
5170 *
5171 * Therefore the above can be simplified as:
5172 *
5173 * ```js
5174 *   var myModule = angular.module(...);
5175 *
5176 *   myModule.directive('directiveName', function factory(injectables) {
5177 *     var directiveDefinitionObject = {
5178 *       link: function postLink(scope, iElement, iAttrs) { ... }
5179 *     };
5180 *     return directiveDefinitionObject;
5181 *     // or
5182 *     // return function postLink(scope, iElement, iAttrs) { ... }
5183 *   });
5184 * ```
5185 *
5186 *
5187 *
5188 * ### Directive Definition Object
5189 *
5190 * The directive definition object provides instructions to the {@link ng.$compile
5191 * compiler}. The attributes are:
5192 *
5193 * #### `priority`
5194 * When there are multiple directives defined on a single DOM element, sometimes it
5195 * is necessary to specify the order in which the directives are applied. The `priority` is used
5196 * to sort the directives before their `compile` functions get called. Priority is defined as a
5197 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5198 * are also run in priority order, but post-link functions are run in reverse order. The order
5199 * of directives with the same priority is undefined. The default priority is `0`.
5200 *
5201 * #### `terminal`
5202 * If set to true then the current `priority` will be the last set of directives
5203 * which will execute (any directives at the current priority will still execute
5204 * as the order of execution on same `priority` is undefined).
5205 *
5206 * #### `scope`
5207 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5208 * same element request a new scope, only one new scope is created. The new scope rule does not
5209 * apply for the root of the template since the root of the template always gets a new scope.
5210 *
5211 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5212 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5213 * when creating reusable components, which should not accidentally read or modify data in the
5214 * parent scope.
5215 *
5216 * The 'isolate' scope takes an object hash which defines a set of local scope properties
5217 * derived from the parent scope. These local properties are useful for aliasing values for
5218 * templates. Locals definition is a hash of local scope property to its source:
5219 *
5220 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5221 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5222 *   attribute name is assumed to be the same as the local name.
5223 *   Given `<widget my-attr="hello {{name}}">` and widget definition
5224 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5225 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5226 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5227 *   component scope).
5228 *
5229 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5230 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5231 *   name is specified then the attribute name is assumed to be the same as the local name.
5232 *   Given `<widget my-attr="parentModel">` and widget definition of
5233 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5234 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5235 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5236 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5237 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5238 *
5239 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5240 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5241 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5242 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5243 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5244 *   pass data from the isolated scope via an expression and to the parent scope, this can be
5245 *   done by passing a map of local variable names and values into the expression wrapper fn.
5246 *   For example, if the expression is `increment(amount)` then we can specify the amount value
5247 *   by calling the `localFn` as `localFn({amount: 22})`.
5248 *
5249 *
5250 *
5251 * #### `controller`
5252 * Controller constructor function. The controller is instantiated before the
5253 * pre-linking phase and it is shared with other directives (see
5254 * `require` attribute). This allows the directives to communicate with each other and augment
5255 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5256 *
5257 * * `$scope` - Current scope associated with the element
5258 * * `$element` - Current element
5259 * * `$attrs` - Current attributes object for the element
5260 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5261 *    The scope can be overridden by an optional first argument.
5262 *   `function([scope], cloneLinkingFn)`.
5263 *
5264 *
5265 * #### `require`
5266 * Require another directive and inject its controller as the fourth argument to the linking function. The
5267 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5268 * injected argument will be an array in corresponding order. If no such directive can be
5269 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5270 *
5271 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5272 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5273 * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5274 * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
5275 *   `link` fn if not found.
5276 *
5277 *
5278 * #### `controllerAs`
5279 * Controller alias at the directive scope. An alias for the controller so it
5280 * can be referenced at the directive template. The directive needs to define a scope for this
5281 * configuration to be used. Useful in the case when directive is used as component.
5282 *
5283 *
5284 * #### `restrict`
5285 * String of subset of `EACM` which restricts the directive to a specific directive
5286 * declaration style. If omitted, the default (attributes only) is used.
5287 *
5288 * * `E` - Element name: `<my-directive></my-directive>`
5289 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5290 * * `C` - Class: `<div class="my-directive: exp;"></div>`
5291 * * `M` - Comment: `<!-- directive: my-directive exp -->`
5292 *
5293 *
5294 * #### `template`
5295 * replace the current element with the contents of the HTML. The replacement process
5296 * migrates all of the attributes / classes from the old element to the new one. See the
5297 * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5298 * Directives Guide} for an example.
5299 *
5300 * You can specify `template` as a string representing the template or as a function which takes
5301 * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
5302 * returns a string value representing the template.
5303 *
5304 *
5305 * #### `templateUrl`
5306 * Same as `template` but the template is loaded from the specified URL. Because
5307 * the template loading is asynchronous the compilation/linking is suspended until the template
5308 * is loaded.
5309 *
5310 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5311 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5312 * a string value representing the url.  In either case, the template URL is passed through {@link
5313 * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5314 *
5315 *
5316 * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
5317 * specify where the template should be inserted. Defaults to `false`.
5318 *
5319 * * `true` - the template will replace the current element.
5320 * * `false` - the template will replace the contents of the current element.
5321 *
5322 *
5323 * #### `transclude`
5324 * compile the content of the element and make it available to the directive.
5325 * Typically used with {@link ng.directive:ngTransclude
5326 * ngTransclude}. The advantage of transclusion is that the linking function receives a
5327 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5328 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5329 * scope. This makes it possible for the widget to have private state, and the transclusion to
5330 * be bound to the parent (pre-`isolate`) scope.
5331 *
5332 * * `true` - transclude the content of the directive.
5333 * * `'element'` - transclude the whole element including any directives defined at lower priority.
5334 *
5335 *
5336 * #### `compile`
5337 *
5338 * ```js
5339 *   function compile(tElement, tAttrs, transclude) { ... }
5340 * ```
5341 *
5342 * The compile function deals with transforming the template DOM. Since most directives do not do
5343 * template transformation, it is not used often. The compile function takes the following arguments:
5344 *
5345 *   * `tElement` - template element - The element where the directive has been declared. It is
5346 *     safe to do template transformation on the element and child elements only.
5347 *
5348 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5349 *     between all directive compile functions.
5350 *
5351 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5352 *
5353 * <div class="alert alert-warning">
5354 * **Note:** The template instance and the link instance may be different objects if the template has
5355 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5356 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5357 * should be done in a linking function rather than in a compile function.
5358 * </div>
5359
5360 * <div class="alert alert-warning">
5361 * **Note:** The compile function cannot handle directives that recursively use themselves in their
5362 * own templates or compile functions. Compiling these directives results in an infinite loop and a
5363 * stack overflow errors.
5364 *
5365 * This can be avoided by manually using $compile in the postLink function to imperatively compile
5366 * a directive's template instead of relying on automatic template compilation via `template` or
5367 * `templateUrl` declaration or manual compilation inside the compile function.
5368 * </div>
5369 *
5370 * <div class="alert alert-error">
5371 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5372 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5373 *   to the link function instead.
5374 * </div>
5375
5376 * A compile function can have a return value which can be either a function or an object.
5377 *
5378 * * returning a (post-link) function - is equivalent to registering the linking function via the
5379 *   `link` property of the config object when the compile function is empty.
5380 *
5381 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5382 *   control when a linking function should be called during the linking phase. See info about
5383 *   pre-linking and post-linking functions below.
5384 *
5385 *
5386 * #### `link`
5387 * This property is used only if the `compile` property is not defined.
5388 *
5389 * ```js
5390 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5391 * ```
5392 *
5393 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5394 * executed after the template has been cloned. This is where most of the directive logic will be
5395 * put.
5396 *
5397 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5398 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5399 *
5400 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5401 *     manipulate the children of the element only in `postLink` function since the children have
5402 *     already been linked.
5403 *
5404 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5405 *     between all directive linking functions.
5406 *
5407 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5408 *     element defines a controller. The controller is shared among all the directives, which allows
5409 *     the directives to use the controllers as a communication channel.
5410 *
5411 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5412 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5413 *     parameter of directive controllers.
5414 *     `function([scope], cloneLinkingFn)`.
5415 *
5416 *
5417 * #### Pre-linking function
5418 *
5419 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5420 * compiler linking function will fail to locate the correct elements for linking.
5421 *
5422 * #### Post-linking function
5423 *
5424 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5425 *
5426 * <a name="Attributes"></a>
5427 * ### Attributes
5428 *
5429 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5430 * `link()` or `compile()` functions. It has a variety of uses.
5431 *
5432 * accessing *Normalized attribute names:*
5433 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5434 * the attributes object allows for normalized access to
5435 *   the attributes.
5436 *
5437 * * *Directive inter-communication:* All directives share the same instance of the attributes
5438 *   object which allows the directives to use the attributes object as inter directive
5439 *   communication.
5440 *
5441 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5442 *   allowing other directives to read the interpolated value.
5443 *
5444 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5445 *   that contain interpolation (e.g. `src="{{bar}}
5445"`). Not only is this very efficient but it's also
5446 *   the only way to easily get the actual value because during the linking phase the interpolation
5447 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5448 *
5449 * ```js
5450 * function linkingFn(scope, elm, attrs, ctrl) {
5451 *   // get the attribute value
5452 *   console.log(attrs.ngModel);
5453 *
5454 *   // change the attribute
5455 *   attrs.$set('ngModel', 'new value');
5456 *
5457 *   // observe changes to interpolated attribute
5458 *   attrs.$observe('ngModel', function(value) {
5459 *     console.log('ngModel has changed value to ' + value);
5460 *   });
5461 * }
5462 * ```
5463 *
5464 * Below is an example using `$compileProvider`.
5465 *
5466 * <div class="alert alert-warning">
5467 * **Note**: Typically directives are registered with `module.directive`. The example below is
5468 * to illustrate how `$compile` works.
5469 * </div>
5470 *
5471 <example module="compile">
5472   <file name="index.html">
5473    <script>
5474      angular.module('compile', [], function($compileProvider) {
5475        // configure new 'compile' directive by passing a directive
5476        // factory function. The factory function injects the '$compile'
5477        $compileProvider.directive('compile', function($compile) {
5478          // directive factory creates a link function
5479          return function(scope, element, attrs) {
5480            scope.$watch(
5481              function(scope) {
5482                 // watch the 'compile' expression for changes
5483                return scope.$eval(attrs.compile);
5484              },
5485              function(value) {
5486                // when the 'compile' expression changes
5487                // assign it into the current DOM
5488                element.html(value);
5489
5490                // compile the new DOM and link it to the current
5491                // scope.
5492                // NOTE: we only compile .childNodes so that
5493                // we don't get into infinite loop compiling ourselves
5494                $compile(element.contents())(scope);
5495              }
5496            );
5497          };
5498        })
5499      });
5500
5501      function Ctrl($scope) {
5502        $scope.name = 'Angular';
5503        $scope.html = 'Hello {{name}}';
5504      }
5505    </script>
5506    <div ng-controller="Ctrl">
5507      <input ng-model="name"> <br>
5508      <textarea ng-model="html"></textarea> <br>
5509      <div compile="html"></div>
5510    </div>
5511   </file>
5512   <file name="protractor.js" type="protractor">
5513     it('should auto compile', function() {
5514       var textarea = $('textarea');
5515       var output = $('div[compile]');
5516       // The initial state reads 'Hello Angular'.
5517       expect(output.getText()).toBe('Hello Angular');
5518       textarea.clear();
5519       textarea.sendKeys('{{name}}!');
5520       expect(output.getText()).toBe('Angular!');
5521     });
5522   </file>
5523 </example>
5524
5525 *
5526 *
5527 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5528 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5529 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5530 *                 root element(s), not their children)
5531 * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5532 * (a DOM element/tree) to a scope. Where:
5533 *
5534 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5535 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5536 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5537 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5538 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5539 *
5540 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5541 *      * `scope` - is the current scope with which the linking function is working with.
5542 *
5543 * Calling the linking function returns the element of the template. It is either the original
5544 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5545 *
5546 * After linking the view is not updated until after a call to $digest which typically is done by
5547 * Angular automatically.
5548 *
5549 * If you need access to the bound view, there are two ways to do it:
5550 *
5551 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5552 *   before you send them to the compiler and keep this reference around.
5553 *   ```js
5554 *     var element = $compile('<p>{{total}}</p>')(scope);
5555 *   ```
5556 *
5557 * - if on the other hand, you need the element to be cloned, the view reference from the original
5558 *   example would not point to the clone, but rather to the original template that was cloned. In
5559 *   this case, you can access the clone via the cloneAttachFn:
5560 *   ```js
5561 *     var templateElement = angular.element('<p>{{total}}</p>'),
5562 *         scope = ....;
5563 *
5564 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5565 *       //attach the clone to DOM document at the right place
5566 *     });
5567 *
5568 *     //now we have reference to the cloned DOM via `clonedElement`
5569 *   ```
5570 *
5571 *
5572 * For information on how the compiler works, see the
5573 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5574 */
5575
5576var $compileMinErr = minErr('$compile');
5577
5578/**
5579 * @ngdoc provider
5580 * @name $compileProvider
5581 * @kind function
5582 *
5583 * @description
5584 */
vendor: 4,668 bytes, lines 5585-5693
5585$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5586function $CompileProvider($provide, $$sanitizeUriProvider) {
5587  var hasDirectives = {},
5588      Suffix = 'Directive',
5589      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
5590      CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
5591
5592  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5593  // The assumption is that future DOM event attribute names will begin with
5594  // 'on' and be composed of only English letters.
5595  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5596
5597  /**
5598   * @ngdoc method
5599   * @name $compileProvider#directive
5600   * @kind function
5601   *
5602   * @description
5603   * Register a new directive with the compiler.
5604   *
5605   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5606   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5607   *    names and the values are the factories.
5608   * @param {Function|Array} directiveFactory An injectable directive factory function. See
5609   *    {@link guide/directive} for more info.
5610   * @returns {ng.$compileProvider} Self for chaining.
5611   */
5612   this.directive = function registerDirective(name, directiveFactory) {
5613    assertNotHasOwnProperty(name, 'directive');
5614    if (isString(name)) {
5615      assertArg(directiveFactory, 'directiveFactory');
5616      if (!hasDirectives.hasOwnProperty(name)) {
5617        hasDirectives[name] = [];
5618        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5619          function($injector, $exceptionHandler) {
5620            var directives = [];
5621            forEach(hasDirectives[name], function(directiveFactory, index) {
5622              try {
5623                var directive = $injector.invoke(directiveFactory);
5624                if (isFunction(directive)) {
5625                  directive = { compile: valueFn(directive) };
5626                } else if (!directive.compile && directive.link) {
5627                  directive.compile = valueFn(directive.link);
5628                }
5629                directive.priority = directive.priority || 0;
5630                directive.index = index;
5631                directive.name = directive.name || name;
5632                directive.require = directive.require || (directive.controller && directive.name);
5633                directive.restrict = directive.restrict || 'A';
5634                directives.push(directive);
5635              } catch (e) {
5636                $exceptionHandler(e);
5637              }
5638            });
5639            return directives;
5640          }]);
5641      }
5642      hasDirectives[name].push(directiveFactory);
5643    } else {
5644      forEach(name, reverseParams(registerDirective));
5645    }
5646    return this;
5647  };
5648
5649
5650  /**
5651   * @ngdoc method
5652   * @name $compileProvider#aHrefSanitizationWhitelist
5653   * @kind function
5654   *
5655   * @description
5656   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5657   * urls during a[href] sanitization.
5658   *
5659   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5660   *
5661   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5662   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5663   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5664   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5665   *
5666   * @param {RegExp=} regexp New regexp to whitelist urls with.
5667   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5668   *    chaining otherwise.
5669   */
5670  this.aHrefSanitizationWhitelist = function(regexp) {
5671    if (isDefined(regexp)) {
5672      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5673      return this;
5674    } else {
5675      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5676    }
5677  };
5678
5679
5680  /**
5681   * @ngdoc method
5682   * @name $compileProvider#imgSrcSanitizationWhitelist
5683   * @kind function
5684   *
5685   * @description
5686   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5687   * urls during img[src] sanitization.
5688   *
5689   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5690   *
5691   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5692   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5693   * regular expression. If a match is found, the original url is 
5693written into the dom. Otherwise,
5694   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5695   *
5696   * @param {RegExp=} regexp New regexp to whitelist urls with.
5697   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5698   *    chaining otherwise.
5699   */
5700  this.imgSrcSanitizationWhitelist = function(regexp) {
5701    if (isDefined(regexp)) {
5702      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5703      return this;
5704    } else {
5705      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5706    }
5707  };
5708
5709  this.$get = [
5710            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5711            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5712    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5713             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5714
5715    var Attributes = function(element, attr) {
5716      this.$$element = element;
5717      this.$attr = attr || {};
5718    };
5719
5720    Attributes.prototype = {
5721      $normalize: directiveNormalize,
5722
5723
5724      /**
5725       * @ngdoc method
5726       * @name $compile.directive.Attributes#$addClass
5727       * @kind function
5728       *
5729       * @description
5730       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5731       * are enabled then an animation will be triggered for the class addition.
5732       *
5733       * @param {string} classVal The className value that will be added to the element
5734       */
5735      $addClass : function(classVal) {
5736        if(classVal && classVal.length > 0) {
5737          $animate.addClass(this.$$element, classVal);
5738        }
5739      },
5740
5741      /**
5742       * @ngdoc method
5743       * @name $compile.directive.Attributes#$removeClass
5744       * @kind function
5745       *
5746       * @description
5747       * Removes the CSS class value specified by the classVal parameter from the element. If
5748       * animations are enabled then an animation will be triggered for the class removal.
5749       *
5750       * @param {string} classVal The className value that will be removed from the element
5751       */
5752      $removeClass : function(classVal) {
5753        if(classVal && classVal.length > 0) {
5754          $animate.removeClass(this.$$element, classVal);
5755        }
5756      },
5757
5758      /**
5759       * @ngdoc method
5760       * @name $compile.directive.Attributes#$updateClass
5761       * @kind function
5762       *
5763       * @description
5764       * Adds and removes the appropriate CSS class values to the element based on the difference
5765       * between the new and old CSS class values (specified as newClasses and oldClasses).
5766       *
5767       * @param {string} newClasses The current CSS className value
5768       * @param {string} oldClasses The former CSS className value
5769       */
5770      $updateClass : function(newClasses, oldClasses) {
5771        var toAdd = tokenDifference(newClasses, oldClasses);
5772        var toRemove = tokenDifference(oldClasses, newClasses);
5773
5774        if(toAdd.length === 0) {
5775          $animate.removeClass(this.$$element, toRemove);
5776        } else if(toRemove.length === 0) {
5777          $animate.addClass(this.$$element, toAdd);
5778        } else {
5779          $animate.setClass(this.$$element, toAdd, toRemove);
5780        }
5781      },
5782
5783      /**
5784       * Set a normalized attribute on the element in a way such that all directives
5785       * can share the attribute. This function properly handles boolean attributes.
5786       * @param {string} key Normalized key. (ie ngAttribute)
5787       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5788       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5789       *     Defaults to true.
5790       * @param {string=} attrName Optional none normalized name. Defaults to key.
5791       */
5792      $set: function(key, value, writeAttr, attrName) {
5793        // TODO: decide whether or not to throw an error if "class"
5794        //is set through this function since it may cause $updateClass to
5795        //become unstable.
5796
5797        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5798            normalizedVal,
5799            nodeName;
5800
5801        if (booleanKey) {
5802          this.$$element.prop(key, value);
5803          attrName = booleanKey;
5804        }
5805
5806        this[key] = value;
5807
5808        // translate normalized key to actual key
5809        if (attrName) {
5810          this.$attr[key] = attrName;
5811        } else {
5812          attrName = this.$attr[key];
5813          if (!attrName) {
5814            this.$attr[key] = attrName = snake_case(key, '-');
5815          }
5816        }
5817
5818        nodeName = nodeName_(this.$$element);
5819
5820        // sanitize a[href] and img[src] values
5821        if ((nodeName === 'A' && key === 'href') ||
5822            (nodeName === 'IMG' && key === 'src')) {
5823          this[key] = value = $$sanitizeUri(value, key === 'src');
5824        }
5825
5826        if (writeAttr !== false) {
5827          if (value === null || value === undefined) {
5828            this.$$element.removeAttr(attrName);
5829          } else {
5830            this.$$element.attr(attrName, value);
5831          }
5832        }
5833
5834        // fire observers
5835        var $$observers = this.$$observers;
5836        $$observers && forEach($$observers[key], function(fn) {
5837          try {
5838            fn(value);
5839          } catch (e) {
5840            $exceptionHandler(e);
5841          }
5842        });
5843      },
5844
5845
5846      /**
5847       * @ngdoc method
5848       * @name $compile.directive.Attributes#$observe
5849       * @kind function
5850       *
5851       * @description
5852       * Observes an interpolated attribute.
5853       *
5854       * The observer function will be invoked once during the next `$digest` following
5855       * compilation. The observer is then invoked whenever the interpolated value
5856       * changes.
5857       *
5858       * @param {string} key Normalized key. (ie ngAttribute) .
5859       * @param {function(interpolatedValue)} fn Function that will be called whenever
5860                the interpolated value of the attribute changes.
5861       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5862       * @returns {function()} the `fn` parameter.
5863       */
5864      $observe: function(key, fn) {
5865        var attrs = this,
5866            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5867            listeners = ($$observers[key] || ($$observers[key] = []));
5868
5869        listeners.push(fn);
5870        $rootScope.$evalAsync(function() {
5871          if (!listeners.$$inter) {
5872            // no one registered attribute interpolation function, so lets call it manually
5873            fn(attrs[key]);
5874          }
5875        });
5876        return fn;
5877      }
5878    };
5879
5880    var startSymbol = $interpolate.startSymbol(),
5881        endSymbol = $interpolate.endSymbol(),
5882        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5883            ? identity
5884            : function denormalizeTemplate(template) {
5885              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5886        },
5887        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5888
5889
5890    return compile;
5891
5892    //================================
5893
5894    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5895                        previousCompileContext) {
5896      if (!($compileNodes instanceof jqLite)) {
5897        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5898        // modify it.
5899        $compileNodes = jqLite($compileNodes);
5900      }
5901      // We can not compile top level text elements since text nodes can be merged and we will
5902      // not be able to attach scope data to them, so we will wrap them in <span>
5903      forEach($compileNodes, function(node, index){
5904        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5905          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5906        }
5907      });
5908      var compositeLinkFn =
5909              compileNodes($compileNodes, transcludeFn, $compileNodes,
5910                           maxPriority, ignoreDirective, previousCompileContext);
5911      safeAddClass($compileNodes, 'ng-scope');
5912      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
5913        assertArg(scope, 'scope');
5914        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5915        // and sometimes changes the structure of the DOM.
5916        var $linkNode = cloneConnectFn
5917          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5918          : $compileNodes;
5919
5920        forEach(transcludeControllers, function(instance, name) {
5921          $linkNode.data('$' + name + 'Controller', instance);
5922        });
5923
5924        // Attach scope only to non-text nodes.
5925        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5926          var node = $linkNode[i],
5927              nodeType = node.nodeType;
5928          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5929            $linkNode.eq(i).data('$scope', scope);
5930          }
5931        }
5932
5933        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5934        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
5935        return $linkNode;
5936      };
5937    }
5938
5939    function safeAddClass($element, className) {
5940      try {
5941        $element.addClass(className);
5942      } catch(e) {
5943        // ignore, since it means that we are trying to set class on
5944        // SVG element, where class name is read-only.
5945      }
5946    }
5947
5948    /**
5949     * Compile function matches each node in nodeList against the directives. Once all directives
5950     * for a particular node are collected their compile functions are executed. The compile
5951     * functions return values - the linking functions - are combined into a composite linking
5952     * function, which is the a linking function for the node.
5953     *
5954     * @param {NodeList} nodeList an array of nodes or NodeList to compile
5955     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
5956     *        scope argument is auto-generated to the new child of the transcluded parent scope.
5957     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
5958     *        the rootElement must be set the jqLite collection of the compile root. This is
5959     *        needed so that the jqLite collection items can be replaced with widgets.
5960     * @param {number=} maxPriority Max directive priority.
5961     * @returns {Function} A composite linking function of all of the matched directives or null.
5962     */
5963    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
5964                            previousCompileContext) {
5965      var linkFns = [],
5966          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
5967
5968      for (var i = 0; i < nodeList.length; i++) {
5969        attrs = new Attributes();
5970
5971        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
5972        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
5973                                        ignoreDirective);
5974
5975        nodeLinkFn = (directives.length)
5976            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
5977                                      null, [], [], previousCompileContext)
5978            : null;
5979
5980        if (nodeLinkFn && nodeLinkFn.scope) {
5981          safeAddClass(jqLite(nodeList[i]), 'ng-scope');
5982        }
5983
5984        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
5985                      !(childNodes = nodeList[i].childNodes) ||
5986                      !childNodes.length)
5987            ? null
5988            : compileNodes(childNodes,
5989                 nodeLinkFn ? (
5990                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
5991                     && nodeLinkFn.transclude) : transcludeFn);
5992
5993        linkFns.push(nodeLinkFn, childLinkFn);
5994        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
5995        //use the previous context only for the first element in the virtual group
5996        previousCompileContext = null;
5997      }
5998
5999      // return a linking function if we have found anything, null otherwise
6000      return linkFnFound ? compositeLinkFn : null;
6001
6002      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
6003        var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;
6004
6005        // copy nodeList so that linking doesn't break due to live list updates.
6006        var nodeListLength = nodeList.length,
6007            stableNodeList = new Array(nodeListLength);
6008        for (i = 0; i < nodeListLength; i++) {
6009          stableNodeList[i] = nodeList[i];
6010        }
6011
6012        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
6013          node = stableNodeList[n];
6014          nodeLinkFn = linkFns[i++];
6015          childLinkFn = linkFns[i++];
6016          $node = jqLite(node);
6017
6018          if (nodeLinkFn) {
6019            if (nodeLinkFn.scope) {
6020              childScope = scope.$new();
6021              $node.data('$scope', childScope);
6022            } else {
6023              childScope = scope;
6024            }
6025
6026            if ( nodeLinkFn.transcludeOnThisElement ) {
6027              childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
6028
6029            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
6030              childBoundTranscludeFn = parentBoundTranscludeFn;
6031
6032            } else if (!parentBoundTranscludeFn && transcludeFn) {
6033              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
6034
6035            } else {
6036              childBoundTranscludeFn = null;
6037            }
6038
6039            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
6040
6041          } else if (childLinkFn) {
6042            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
6043          }
6044        }
6045      }
6046    }
6047
6048    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
6049
6050      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
6051        var scopeCreated = false;
6052
6053        if (!transcludedScope) {
6054          transcludedScope = scope.$new();
6055          transcludedScope.$$transcluded = true;
6056          scopeCreated = true;
6057        }
6058
6059        var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
6060        if (scopeCreated) {
6061          clone.on('$destroy', function() { transcludedScope.$destroy(); });
6062        }
6063        return clone;
6064      };
6065
6066      return boundTranscludeFn;
6067    }
6068
6069    /**
6070     * Looks for directives on the given node and adds them to the directive collection which is
6071     * sorted.
6072     *
6073     * @param node Node to search.
6074     * @param directives An array to which the directives are added to. This array is sorted before
6075     *        the function returns.
6076     * @param attrs The shared attrs object which is used to populate the normalized attributes.
6077     * @param {number=} maxPriority Max directive priority.
6078     */
6079    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6080      var nodeType = node.nodeType,
6081          attrsMap = attrs.$attr,
6082          match,
6083          className;
6084
6085      switch(nodeType) {
6086        case 1: /* Element */
6087          // use the node name: <directive>
6088          addDirective(directives,
6089              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6090
6091          // iterate over the attributes
6092          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
6093                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6094            var attrStartName = false;
6095            var attrEndName = false;
6096
6097            attr = nAttrs[j];
6098            if (!msie || msie >= 8 || attr.specified) {
6099              name = attr.name;
6100              value = trim(attr.value);
6101
6102              // support ngAttr attribute binding
6103              ngAttrName = directiveNormalize(name);
6104              if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
6105                name = snake_case(ngAttrName.substr(6), '-');
6106              }
6107
6108              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6109              if (ngAttrName === directiveNName + 'Start') {
6110                attrStartName = name;
6111                attrEndName = name.substr(0, name.length - 5) + 'end';
6112                name = name.substr(0, name.length - 6);
6113              }
6114
6115              nName = directiveNormalize(name.toLowerCase());
6116              attrsMap[nName] = name;
6117              if (isNgAttr || !attrs.hasOwnProperty(nName)) {
6118                  attrs[nName] = value;
6119                  if (getBooleanAttrName(node, nName)) {
6120                    attrs[nName] = true; // presence means true
6121                  }
6122              }
6123              addAttrInterpolateDirective(node, directives, value, nName);
6124              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6125                            attrEndName);
6126            }
6127          }
6128
6129          // use class as directive
6130          className = node.className;
6131          if (isString(className) && className !== '') {
6132            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6133              nName = directiveNormalize(match[2]);
6134              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6135                attrs[nName] = trim(match[3]);
6136              }
6137              className = className.substr(match.index + match[0].length);
6138            }
6139          }
6140          break;
6141        case 3: /* Text Node */
6142          addTextInterpolateDirective(directives, node.nodeValue);
6143          break;
6144        case 8: /* Comment */
6145          try {
6146            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6147            if (match) {
6148              nName = directiveNormalize(match[1]);
6149              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6150                attrs[nName] = trim(match[2]);
6151              }
6152            }
6153          } catch (e) {
6154            // turns out that under some circumstances IE9 throws errors when one attempts to read
6155            // comment's node value.
6156            // Just ignore it and continue. (Can't seem to reproduce in test case.)
6157          }
6158          break;
6159      }
6160
6161      directives.sort(byPriority);
6162      return directives;
6163    }
6164
6165    /**
6166     * Given a node with an directive-start it collects all of the siblings until it finds
6167     * directive-end.
6168     * @param node
6169     * @param attrStart
6170     * @param attrEnd
6171     * @returns {*}
6172     */
6173    function groupScan(node, attrStart, attrEnd) {
6174      var nodes = [];
6175      var depth = 0;
6176      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6177        var startNode = node;
6178        do {
6179          if (!node) {
6180            throw $compileMinErr('uterdir',
6181                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6182                      attrStart, attrEnd);
6183          }
6184          if (node.nodeType == 1 /** Element **/) {
6185            if (node.hasAttribute(attrStart)) depth++;
6186            if (node.hasAttribute(attrEnd)) depth--;
6187          }
6188          nodes.push(node);
6189          node = node.nextSibling;
6190        } while (depth > 0);
6191      } else {
6192        nodes.push(node);
6193      }
6194
6195      return jqLite(nodes);
6196    }
6197
6198    /**
6199     * Wrapper for linking function which converts normal linking function into a grouped
6200     * linking function.
6201     * @param linkFn
6202     * @param attrStart
6203     * @param attrEnd
6204     * @returns {Function}
6205     */
6206    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6207      return function(scope, element, attrs, controllers, transcludeFn) {
6208        element = groupScan(element[0], attrStart, attrEnd);
6209        return linkFn(scope, element, attrs, controllers, transcludeFn);
6210      };
6211    }
6212
6213    /**
6214     * Once the directives have been collected, their compile functions are executed. This method
6215     * is responsible for inlining directive templates as well as terminating the application
6216     * of the directives if the terminal directive has been reached.
6217     *
6218     * @param {Array} directives Array of collected directives to execute their compile function.
6219     *        this needs to be pre-sorted by priority order.
6220     * @param {Node} compileNode The raw DOM node to apply the compile functions to
6221     * @param {Object} templateAttrs The shared attribute function
6222     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6223     *                                                  scope argument is auto-generated to the new
6224     *                                                  child of the transcluded parent scope.
6225     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6226     *                              argument has the root jqLite array so that we can replace nodes
6227     *                              on it.
6228     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6229     *                                           compiling the transclusion.
6230     * @param {Array.<Function>} preLinkFns
6231     * @param {Array.<Function>} postLinkFns
6232     * @param {Object} previousCompileContext Context used for previous compilation of the current
6233     *                                        node
6234     * @returns {Function} linkFn
6235     */
6236    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
6237                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
6238                                   previousCompileContext) {
6239      previousCompileContext = previousCompileContext || {};
6240
6241      var terminalPriority = -Number.MAX_VALUE,
6242          newScopeDirective,
6243          controllerDirectives = previousCompileContext.controllerDirectives,
6244          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6245          templateDirective = previousCompileContext.templateDirective,
6246          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6247          hasTranscludeDirective = false,
6248          hasTemplate = false,
6249          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6250          $compileNode = templateAttrs.$$element = jqLite(compileNode),
6251          directive,
6252          directiveName,
6253          $template,
6254          replaceDirective = originalReplaceDirective,
6255          childTranscludeFn = transcludeFn,
6256          linkFn,
6257          directiveValue;
6258
6259      // executes all directives on the current element
6260      for(var i = 0, ii = directives.length; i < ii; i++) {
6261        directive = directives[i];
6262        var attrStart = directive.$$start;
6263        var attrEnd = directive.$$end;
6264
6265        // collect multiblock sections
6266        if (attrStart) {
6267          $compileNode = groupScan(compileNode, attrStart, attrEnd);
6268        }
6269        $template = undefined;
6270
6271        if (terminalPriority > directive.priority) {
6272          break; // prevent further processing of directives
6273        }
6274
6275        if (directiveValue = directive.scope) {
6276          newScopeDirective = newScopeDirective || directive;
6277
6278          // skip the check for directives with async templates, we'll check the derived sync
6279          // directive when the template arrives
6280          if (!directive.templateUrl) {
6281            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6282                              $compileNode);
6283            if (isObject(directiveValue)) {
6284              newIsolateScopeDirective = directive;
6285            }
6286          }
6287        }
6288
6289        directiveName = directive.name;
6290
6291        if (!directive.templateUrl && directive.controller) {
6292          directiveValue = directive.controller;
6293          controllerDirectives = controllerDirectives || {};
6294          assertNoDuplicate("'" + directiveName + "' controller",
6295              controllerDirectives[directiveName], directive, $compileNode);
6296          controllerDirectives[directiveName] = directive;
6297        }
6298
6299        if (directiveValue = directive.transclude) {
6300          hasTranscludeDirective = true;
6301
6302          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6303          // This option should only be used by directives that know how to safely handle element transclusion,
6304          // where the transcluded nodes are added or replaced after linking.
6305          if (!directive.$$tlb) {
6306            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6307            nonTlbTranscludeDirective = directive;
6308          }
6309
6310          if (directiveValue == 'element') {
6311            hasElementTranscludeDirective = true;
6312            terminalPriority = directive.priority;
6313            $template = groupScan(compileNode, attrStart, attrEnd);
6314            $compileNode = templateAttrs.$$element =
6315                jqLite(document.createComment(' ' + directiveName + ': ' +
6316                                              templateAttrs[directiveName] + ' '));
6317            compileNode = $compileNode[0];
6318            replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
6319
6320            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6321                                        replaceDirective && replaceDirective.name, {
6322                                          // Don't pass in:
6323                                          // - controllerDirectives - otherwise we'll create duplicates controllers
6324                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 4,711 bytes, lines 6324-6431
6324ining templates with
6325                                          //   element transclusion doesn't make sense.
6326                                          //
6327                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6328                                          // on the same element more than once.
6329                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
6330                                        });
6331          } else {
6332            $template = jqLite(jqLiteClone(compileNode)).contents();
6333            $compileNode.empty(); // clear contents
6334            childTranscludeFn = compile($template, transcludeFn);
6335          }
6336        }
6337
6338        if (directive.template) {
6339          hasTemplate = true;
6340          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6341          templateDirective = directive;
6342
6343          directiveValue = (isFunction(directive.template))
6344              ? directive.template($compileNode, templateAttrs)
6345              : directive.template;
6346
6347          directiveValue = denormalizeTemplate(directiveValue);
6348
6349          if (directive.replace) {
6350            replaceDirective = directive;
6351            if (jqLiteIsTextNode(directiveValue)) {
6352              $template = [];
6353            } else {
6354              $template = jqLite(trim(directiveValue));
6355            }
6356            compileNode = $template[0];
6357
6358            if ($template.length != 1 || compileNode.nodeType !== 1) {
6359              throw $compileMinErr('tplrt',
6360                  "Template for directive '{0}' must have exactly one root element. {1}",
6361                  directiveName, '');
6362            }
6363
6364            replaceWith(jqCollection, $compileNode, compileNode);
6365
6366            var newTemplateAttrs = {$attr: {}};
6367
6368            // combine directives from the original node and from the template:
6369            // - take the array of directives for this element
6370            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6371            // - collect directives from the template and sort them by priority
6372            // - combine directives as: processed + template + unprocessed
6373            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6374            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6375
6376            if (newIsolateScopeDirective) {
6377              markDirectivesAsIsolate(templateDirectives);
6378            }
6379            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6380            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6381
6382            ii = directives.length;
6383          } else {
6384            $compileNode.html(directiveValue);
6385          }
6386        }
6387
6388        if (directive.templateUrl) {
6389          hasTemplate = true;
6390          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6391          templateDirective = directive;
6392
6393          if (directive.replace) {
6394            replaceDirective = directive;
6395          }
6396
6397          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6398              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
6399                controllerDirectives: controllerDirectives,
6400                newIsolateScopeDirective: newIsolateScopeDirective,
6401                templateDirective: templateDirective,
6402                nonTlbTranscludeDirective: nonTlbTranscludeDirective
6403              });
6404          ii = directives.length;
6405        } else if (directive.compile) {
6406          try {
6407            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6408            if (isFunction(linkFn)) {
6409              addLinkFns(null, linkFn, attrStart, attrEnd);
6410            } else if (linkFn) {
6411              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6412            }
6413          } catch (e) {
6414            $exceptionHandler(e, startingTag($compileNode));
6415          }
6416        }
6417
6418        if (directive.terminal) {
6419          nodeLinkFn.terminal = true;
6420          terminalPriority = Math.max(terminalPriority, directive.priority);
6421        }
6422
6423      }
6424
6425      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6426      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
6427      nodeLinkFn.templateOnThisElement = hasTemplate;
6428      nodeLinkFn.transclude = childTranscludeFn;
6429
6430      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6431
6432      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6433      return nodeLinkFn;
6434
6435      ////////////////////
6436
6437      function addLinkFns(pre, post, attrStart, attrEnd) {
6438        if (pre) {
6439          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6440          pre.require = directive.require;
6441          pre.directiveName = directiveName;
6442          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6443            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6444          }
6445          preLinkFns.push(pre);
6446        }
6447        if (post) {
6448          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6449          post.require = directive.require;
6450          post.directiveName = directiveName;
6451          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6452            post = cloneAndAnnotateFn(post, {isolateScope: true});
6453          }
6454          postLinkFns.push(post);
6455        }
6456      }
6457
6458
6459      function getControllers(directiveName, require, $element, elementControllers) {
6460        var value, retrievalMethod = 'data', optional = false;
6461        if (isString(require)) {
6462          while((value = require.charAt(0)) == '^' || value == '?') {
6463            require = require.substr(1);
6464            if (value == '^') {
6465              retrievalMethod = 'inheritedData';
6466            }
6467            optional = optional || value == '?';
6468          }
6469          value = null;
6470
6471          if (elementControllers && retrievalMethod === 'data') {
6472            value = elementControllers[require];
6473          }
6474          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6475
6476          if (!value && !optional) {
6477            throw $compileMinErr('ctreq',
6478                "Controller '{0}', required by directive '{1}', can't be found!",
6479                require, directiveName);
6480          }
6481          return value;
6482        } else if (isArray(require)) {
6483          value = [];
6484          forEach(require, function(require) {
6485            value.push(getControllers(directiveName, require, $element, elementControllers));
6486          });
6487        }
6488        return value;
6489      }
6490
6491
6492      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6493        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6494
6495        if (compileNode === linkNode) {
6496          attrs = templateAttrs;
6497        } else {
6498          attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6499        }
6500        $element = attrs.$$element;
6501
6502        if (newIsolateScopeDirective) {
6503          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6504          var $linkNode = jqLite(linkNode);
6505
6506          isolateScope = scope.$new(true);
6507
6508          if (templateDirective && (templateDirective === newIsolateScopeDirective ||
6509              templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6510            $linkNode.data('$isolateScope', isolateScope) ;
6511          } else {
6512            $linkNode.data('$isolateScopeNoTemplate', isolateScope);
6513          }
6514
6515
6516
6517          safeAddClass($linkNode, 'ng-isolate-scope');
6518
6519          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6520            var match = definition.match(LOCAL_REGEXP) || [],
6521                attrName = match[3] || scopeName,
6522                optional = (match[2] == '?'),
6523                mode = match[1], // @, =, or &
6524                lastValue,
6525                parentGet, parentSet, compare;
6526
6527            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6528
6529            switch (mode) {
6530
6531              case '@':
6532                attrs.$observe(attrName, function(value) {
6533                  isolateScope[scopeName] = value;
6534                });
6535                attrs.$$observers[attrName].$$scope = scope;
6536                if( attrs[attrName] ) {
6537                  // If the attribute has been provided then we trigger an interpolation to ensure
6538                  // the value is there for use in the link fn
6539                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6540                }
6541                break;
6542
6543              case '=':
6544                if (optional && !attrs[attrName]) {
6545                  return;
6546                }
6547                parentGet = $parse(attrs[attrName]);
6548                if (parentGet.literal) {
6549                  compare = equals;
6550                } else {
6551                  compare = function(a,b) { return a === b; };
6552                }
6553                parentSet = parentGet.assign || function() {
6554                  // reset the change, or we will throw this exception on every $digest
6555                  lastValue = isolateScope[scopeName] = parentGet(scope);
6556                  throw $compileMinErr('nonassign',
6557                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6558                      attrs[attrName], newIsolateScopeDirective.name);
6559                };
6560                lastValue = isolateScope[scopeName] = parentGet(scope);
6561                isolateScope.$watch(function parentValueWatch() {
6562                  var parentValue = parentGet(scope);
6563                  if (!compare(parentValue, isolateScope[scopeName])) {
6564                    // we are out of sync and need to copy
6565                    if (!compare(parentValue, lastValue)) {
6566                      // parent changed and it has precedence
6567                      isolateScope[scopeName] = parentValue;
6568                    } else {
6569                      // if the parent can be assigned then do so
6570                      parentSet(scope, parentValue = isolateScope[scopeName]);
6571                    }
6572                  }
6573                  return lastValue = parentValue;
6574                }, null, parentGet.literal);
6575                break;
6576
6577              case '&':
6578                parentGet = $parse(attrs[attrName]);
6579                isolateScope[scopeName] = function(locals) {
6580                  return parentGet(scope, locals);
6581                };
6582                break;
6583
6584              default:
6585                throw $compileMinErr('iscp',
6586                    "Invalid isolate scope definition for directive '{0}'." +
6587                    " Definition: {... {1}: '{2}' ...}",
6588                    newIsolateScopeDirective.name, scopeName, definition);
6589            }
6590          });
6591        }
6592        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6593        if (controllerDirectives) {
6594          forEach(controllerDirectives, function(directive) {
6595            var locals = {
6596              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6597              $element: $element,
6598              $attrs: attrs,
6599              $transclude: transcludeFn
6600            }, controllerInstance;
6601
6602            controller = directive.controller;
6603            if (controller == '@') {
6604              controller = attrs[directive.name];
6605            }
6606
6607            controllerInstance = $controller(controller, locals);
6608            // For directives with element transclusion the element is a comment,
6609            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6610            // clean up (http://bugs.jquery.com/ticket/8335).
6611            // Instead, we save the controllers for the element in a local hash and attach to .data
6612            // later, once we have the actual element.
6613            elementControllers[directive.name] = controllerInstance;
6614            if (!hasElementTranscludeDirective) {
6615              $element.data('$' + directive.name + 'Controller', controllerInstance);
6616            }
6617
6618            if (directive.controllerAs) {
6619              locals.$scope[directive.controllerAs] = controllerInstance;
6620            }
6621          });
6622        }
6623
6624        // PRELINKING
6625        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6626          try {
6627            linkFn = preLinkFns[i];
6628            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6629                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6630          } catch (e) {
6631            $exceptionHandler(e, startingTag($element));
6632          }
6633        }
6634
6635        // RECURSION
6636        // We only pass the isolate scope, if the isolate directive has a template,
6637        // otherwise the child elements do not belong to the isolate directive.
6638        var scopeToChild = scope;
6639        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6640          scopeToChild = isolateScope;
6641        }
6642        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6643
6644        // POSTLINKING
6645        for(i = postLinkFns.length - 1; i >= 0; i--) {
6646          try {
6647            linkFn = postLinkFns[i];
6648            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6649                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6650          } catch (e) {
6651            $exceptionHandler(e, startingTag($element));
6652          }
6653        }
6654
6655        // This is the function that is injected as `$transclude`.
6656        function controllersBoundTransclude(scope, cloneAttachFn) {
6657          var transcludeControllers;
6658
6659          // no scope passed
6660          if (arguments.length < 2) {
6661            cloneAttachFn = scope;
6662            scope = undefined;
6663          }
6664
6665          if (hasElementTranscludeDirective) {
6666            transcludeControllers = elementControllers;
6667          }
6668
6669          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6670        }
6671      }
6672    }
6673
6674    function markDirectivesAsIsolate(directives) {
6675      // mark all directives as needing isolate scope.
6676      for (var j = 0, jj = directives.length; j < jj; j++) {
6677        directives[j] = inherit(directives[j], {$$isolateScope: true});
6678      }
6679    }
6680
6681    /**
6682     * looks up the directive and decorates it with exception handling and proper parameters. We
6683     * call this the boundDirective.
6684     *
6685     * @param {string} name name of the directive to look up.
6686     * @param {string} location The directive must be found in specific format.
6687     *   String containing any of theses characters:
6688     *
6689     *   * `E`: element name
6690     *   * `A': attribute
6691     *   * `C`: class
6692     *   * `M`: comment
6693     * @returns {boolean} true if directive was added.
6694     */
6695    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6696                          endAttrName) {
6697      if (name === ignoreDirective) return null;
6698      var match = null;
6699      if (hasDirectives.hasOwnProperty(name)) {
6700        for(var directive, directives = $injector.get(name + Suffix),
6701            i = 0, ii = directives.length; i<ii; i++) {
6702          try {
6703            directive = directives[i];
6704            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6705                 directive.restrict.indexOf(location) != -1) {
6706              if (startAttrName) {
6707                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6708              }
6709              tDirectives.push(directive);
6710              match = directive;
6711            }
6712          } catch(e) { $exceptionHandler(e); }
6713        }
6714      }
6715      return match;
6716    }
6717
6718
6719    /**
6720     * When the element is replaced with HTML template then the new attributes
6721     * on the template need to be merged with the existing attributes in the DOM.
6722     * The desired effect is to have both of the attributes present.
6723     *
6724     * @param {object} dst destination attributes (original DOM)
6725     * @param {object} src source attributes (from the directive template)
6726     */
6727    function mergeTemplateAttributes(dst, src) {
6728      var srcAttr = src.$attr,
6729          dstAttr = dst.$attr,
6730          $element = dst.$$element;
6731
6732      // reapply the old attributes to the new element
6733      forEach(dst, function(value, key) {
6734        if (key.charAt(0) != '$') {
6735          if (src[key] && src[key] !== value) {
6736            value += (key === 'style' ? ';' : ' ') + src[key];
6737          }
6738          dst.$set(key, value, true, srcAttr[key]);
6739        }
6740      });
6741
6742      // copy the new attributes on the old attrs object
6743      forEach(src, function(value, key) {
6744        if (key == 'class') {
6745          safeAddClass($element, value);
6746          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6747        } else if (key == 'style') {
6748          $element.attr('style', $element.attr('style') + ';' + value);
6749          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6750          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6751          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6752          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6753        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6754          dst[key] = value;
6755          dstAttr[key] = srcAttr[key];
6756        }
6757      });
6758    }
6759
6760
6761    function compileTemplateUrl(directives, $compileNode, tAttrs,
6762        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6763      var linkQueue = [],
6764          afterTemplateNodeLinkFn,
6765          afterTemplateChildLinkFn,
6766          beforeTemplateCompileNode = $compileNode[0],
6767          origAsyncDirective = directives.shift(),
6768          // The fact that we have to copy and patch the directive seems wrong!
6769          derivedSyncDirective = extend({}, origAsyncDirective, {
6770            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6771          }),
6772          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6773              ? origAsyncDirective.templateUrl($compileNode, tAttrs
6773)
6774              : origAsyncDirective.templateUrl;
6775
6776      $compileNode.empty();
6777
6778      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6779        success(function(content) {
6780          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6781
6782          content = denormalizeTemplate(content);
6783
6784          if (origAsyncDirective.replace) {
6785            if (jqLiteIsTextNode(content)) {
6786              $template = [];
6787            } else {
6788              $template = jqLite(trim(content));
6789            }
6790            compileNode = $template[0];
6791
6792            if ($template.length != 1 || compileNode.nodeType !== 1) {
6793              throw $compileMinErr('tplrt',
6794                  "Template for directive '{0}' must have exactly one root element. {1}",
6795                  origAsyncDirective.name, templateUrl);
6796            }
6797
6798            tempTemplateAttrs = {$attr: {}};
6799            replaceWith($rootElement, $compileNode, compileNode);
6800            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6801
6802            if (isObject(origAsyncDirective.scope)) {
6803              markDirectivesAsIsolate(templateDirectives);
6804            }
6805            directives = templateDirectives.concat(directives);
6806            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6807          } else {
6808            compileNode = beforeTemplateCompileNode;
6809            $compileNode.html(content);
6810          }
6811
6812          directives.unshift(derivedSyncDirective);
6813
6814          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6815              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6816              previousCompileContext);
6817          forEach($rootElement, function(node, i) {
6818            if (node == compileNode) {
6819              $rootElement[i] = $compileNode[0];
6820            }
6821          });
6822          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6823
6824          while(linkQueue.length) {
6825            var scope = linkQueue.shift(),
6826                beforeTemplateLinkNode = linkQueue.shift(),
6827                linkRootElement = linkQueue.shift(),
6828                boundTranscludeFn = linkQueue.shift(),
6829                linkNode = $compileNode[0];
6830
6831            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6832              var oldClasses = beforeTemplateLinkNode.className;
6833
6834              if (!(previousCompileContext.hasElementTranscludeDirective &&
6835                  origAsyncDirective.replace)) {
6836                // it was cloned therefore we have to clone as well.
6837                linkNode = jqLiteClone(compileNode);
6838              }
6839
6840              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6841
6842              // Copy in CSS classes from original node
6843              safeAddClass(jqLite(linkNode), oldClasses);
6844            }
6845            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6846              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6847            } else {
6848              childBoundTranscludeFn = boundTranscludeFn;
6849            }
6850            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6851              childBoundTranscludeFn);
6852          }
6853          linkQueue = null;
6854        }).
6855        error(function(response, code, headers, config) {
6856          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6857        });
6858
6859      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6860        var childBoundTranscludeFn = boundTranscludeFn;
6861        if (linkQueue) {
6862          linkQueue.push(scope);
6863          linkQueue.push(node);
6864          linkQueue.push(rootElement);
6865          linkQueue.push(childBoundTranscludeFn);
6866        } else {
6867          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6868            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6869          }
6870          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
6871        }
6872      };
6873    }
6874
6875
6876    /**
6877     * Sorting function for bound directives.
6878     */
6879    function byPriority(a, b) {
6880      var diff = b.priority - a.priority;
6881      if (diff !== 0) return diff;
6882      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6883      return a.index - b.index;
6884    }
6885
6886
6887    function assertNoDuplicate(what, previousDirective, directive, element) {
6888      if (previousDirective) {
6889        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6890            previousDirective.name, directive.name, what, startingTag(element));
6891      }
6892    }
6893
6894
6895      function addTextInterpolateDirective(directives, text) {
6896        var interpolateFn = $interpolate(text, true);
6897        if (interpolateFn) {
6898          directives.push({
6899            priority: 0,
6900            compile: function textInterpolateCompileFn(templateNode) {
6901              // when transcluding a template that has bindings in the root
6902              // then we don't have a parent and should do this in the linkFn
6903              var parent = templateNode.parent(), hasCompileParent = parent.length;
6904              if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
6905
6906              return function textInterpolateLinkFn(scope, node) {
6907                var parent = node.parent(),
6908                  bindings = parent.data('$binding') || [];
6909                bindings.push(interpolateFn);
6910                parent.data('$binding', bindings);
6911                if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
6912                scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6913                  node[0].nodeValue = value;
6914                });
6915              };
6916            }
6917          });
6918        }
6919      }
6920
6921
6922    function getTrustedContext(node, attrNormalizedName) {
6923      if (attrNormalizedName == "srcdoc") {
6924        return $sce.HTML;
6925      }
6926      var tag = nodeName_(node);
6927      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6928      if (attrNormalizedName == "xlinkHref" ||
6929          (tag == "FORM" && attrNormalizedName == "action") ||
6930          (tag != "IMG" && (attrNormalizedName == "src" ||
6931                            attrNormalizedName == "ngSrc"))) {
6932        return $sce.RESOURCE_URL;
6933      }
6934    }
6935
6936
6937    function addAttrInterpolateDirective(node, directives, value, name) {
6938      var interpolateFn = $interpolate(value, true);
6939
6940      // no interpolation found -> ignore
6941      if (!interpolateFn) return;
6942
6943
6944      if (name === "multiple" && nodeName_(node) === "SELECT") {
6945        throw $compileMinErr("selmulti",
6946            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6947            startingTag(node));
6948      }
6949
6950      directives.push({
6951        priority: 100,
6952        compile: function() {
6953            return {
6954              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6955                var $$observers = (attr.$$observers || (attr.$$observers = {}));
6956
6957                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
6958                  throw $compileMinErr('nodomevents',
6959                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
6960                          "ng- versions (such as ng-click instead of onclick) instead.");
6961                }
6962
6963                // we need to interpolate again, in case the attribute value has been updated
6964                // (e.g. by another directive's compile function)
6965                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
6966
6967                // if attribute was updated so that there is no interpolation going on we don't want to
6968                // register any observers
6969                if (!interpolateFn) return;
6970
6971                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
6972                // actual attr value
6973                attr[name] = interpolateFn(scope);
6974                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6975                (attr.$$observers && attr.$$observers[name].$$scope || scope).
6976                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6977                    //special case for class attribute addition + removal
6978                    //so that class changes can tap into the animation
6979                    //hooks provided by the $animate service. Be sure to
6980                    //skip animations when the first digest occurs (when
6981                    //both the new and the old values are the same) since
6982                    //the CSS classes are the non-interpolated values
6983                    if(name === 'class' && newValue != oldValue) {
6984                      attr.$updateClass(newValue, oldValue);
6985                    } else {
6986                      attr.$set(name, newValue);
6987                    }
6988                  });
6989              }
6990            };
6991          }
6992      });
6993    }
6994
6995
6996    /**
6997     * This is a special jqLite.replaceWith, which can replace items which
6998     * have no parents, provided that the containing jqLite collection is provided.
6999     *
7000     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
7001     *                               in the root of the tree.
7002     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
7003     *                                  the shell, but replace its DOM node reference.
7004     * @param {Node} newNode The new DOM node.
7005     */
7006    function replaceWith($rootElement, elementsToRemove, newNode) {
7007      var firstElementToRemove = elementsToRemove[0],
7008          removeCount = elementsToRemove.length,
7009          parent = firstElementToRemove.parentNode,
7010          i, ii;
7011
7012      if ($rootElement) {
7013        for(i = 0, ii = $rootElement.length; i < ii; i++) {
7014          if ($rootElement[i] == firstElementToRemove) {
7015            $rootElement[i++] = newNode;
7016            for (var j = i, j2 = j + removeCount - 1,
7017                     jj = $rootElement.length;
7018                 j < jj; j++, j2++) {
7019              if (j2 < jj) {
7020                $rootElement[j] = $rootElement[j2];
7021              } else {
7022                delete $rootElement[j];
7023              }
7024            }
7025            $rootElement.length -= removeCount - 1;
7026            break;
7027          }
7028        }
7029      }
7030
7031      if (parent) {
7032        parent.replaceChild(newNode, firstElementToRemove);
7033      }
7034      var fragment = document.createDocumentFragment();
7035      fragment.appendChild(firstElementToRemove);
7036      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
7037      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
7038        var element = elementsToRemove[k];
7039        jqLite(element).remove(); // must do this way to clean up expando
7040        fragment.appendChild(element);
7041        delete elementsToRemove[k];
7042      }
7043
7044      elementsToRemove[0] = newNode;
7045      elementsToRemove.length = 1;
7046    }
7047
7048
7049    function cloneAndAnnotateFn(fn, annotation) {
7050      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
7051    }
7052  }];
7053}
7054
7055var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
7056/**
7057 * Converts all accepted directives format into proper directive name.
7058 * All of these will become 'myDirective':
7059 *   my:Directive
7060 *   my-directive
7061 *   x-my-directive
7062 *   data-my:directive
7063 *
7064 * Also there is special case for Moz prefix starting with upper case letter.
7065 * @param name Name to normalize
7066 */
7067function directiveNormalize(name) {
7068  return camelCase(name.replace(PREFIX_REGEXP, ''));
7069}
7070
7071/**
7072 * @ngdoc type
7073 * @name $compile.directive.Attributes
7074 *
7075 * @description
7076 * A shared object between directive compile / linking functions which contains 
7076normalized DOM
7077 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
7078 * needed since all of these are treated as equivalent in Angular:
7079 *
7080 * ```
7081 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7082 * ```
7083 */
7084
7085/**
7086 * @ngdoc property
7087 * @name $compile.directive.Attributes#$attr
7088 * @returns {object} A map of DOM element attribute names to the normalized name. This is
7089 *                   needed to do reverse lookup from normalized name back to actual name.
7090 */
7091
7092
7093/**
7094 * @ngdoc method
7095 * @name $compile.directive.Attributes#$set
7096 * @kind function
7097 *
7098 * @description
7099 * Set DOM element attribute value.
7100 *
7101 *
7102 * @param {string} name Normalized element attribute name of the property to modify. The name is
7103 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7104 *          property to the original name.
7105 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7106 */
7107
7108
7109
7110/**
7111 * Closure compiler type information
7112 */
7113
7114function nodesetLinkingFn(
7115  /* angular.Scope */ scope,
7116  /* NodeList */ nodeList,
7117  /* Element */ rootElement,
7118  /* function(Function) */ boundTranscludeFn
7119){}
7120
7121function directiveLinkingFn(
7122  /* nodesetLinkingFn */ nodesetLinkingFn,
7123  /* angular.Scope */ scope,
7124  /* Node */ node,
7125  /* Element */ rootElement,
7126  /* function(Function) */ boundTranscludeFn
7127){}
7128
7129function tokenDifference(str1, str2) {
7130  var values = '',
7131      tokens1 = str1.split(/\s+/),
7132      tokens2 = str2.split(/\s+/);
7133
7134  outer:
7135  for(var i = 0; i < tokens1.length; i++) {
7136    var token = tokens1[i];
7137    for(var j = 0; j < tokens2.length; j++) {
7138      if(token == tokens2[j]) continue outer;
7139    }
7140    values += (values.length > 0 ? ' ' : '') + token;
7141  }
7142  return values;
7143}
7144
7145/**
7146 * @ngdoc provider
7147 * @name $controllerProvider
7148 * @description
7149 * The {@link ng.$controller $controller service} is used by Angular to create new
7150 * controllers.
7151 *
7152 * This provider allows controller registration via the
7153 * {@link ng.$controllerProvider#register register} method.
7154 */
7155function $ControllerProvider() {
7156  var controllers = {},
7157      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7158
7159
7160  /**
7161   * @ngdoc method
7162   * @name $controllerProvider#register
7163   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7164   *    the names and the values are the constructors.
7165   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7166   *    annotations in the array notation).
7167   */
7168  this.register = function(name, constructor) {
7169    assertNotHasOwnProperty(name, 'controller');
7170    if (isObject(name)) {
7171      extend(controllers, name);
7172    } else {
7173      controllers[name] = constructor;
7174    }
7175  };
7176
7177
7178  this.$get = ['$injector', '$window', function($injector, $window) {
7179
7180    /**
7181     * @ngdoc service
7182     * @name $controller
7183     * @requires $injector
7184     *
7185     * @param {Function|string} constructor If called with a function then it's considered to be the
7186     *    controller constructor function. Otherwise it's considered to be a string which is used
7187     *    to retrieve the controller constructor using the following steps:
7188     *
7189     *    * check if a controller with given name is registered via `$controllerProvider`
7190     *    * check if evaluating the string on the current scope returns a constructor
7191     *    * check `window[constructor]` on the global `window` object
7192     *
7193     * @param {Object} locals Injection locals for Controller.
7194     * @return {Object} Instance of given controller.
7195     *
7196     * @description
7197     * `$controller` service is responsible for instantiating controllers.
7198     *
7199     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7200     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7201     */
7202    return function(expression, locals) {
7203      var instance, match, constructor, identifier;
7204
7205      if(isString(expression)) {
7206        match = expression.match(CNTRL_REG),
7207        constructor = match[1],
7208        identifier = match[3];
7209        expression = controllers.hasOwnProperty(constructor)
7210            ? controllers[constructor]
7211            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7212
7213        assertArgFn(expression, constructor, true);
7214      }
7215
7216      instance = $injector.instantiate(expression, locals);
7217
7218      if (identifier) {
7219        if (!(locals && typeof locals.$scope === 'object')) {
7220          throw minErr('$controller')('noscp',
7221              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7222              constructor || expression.name, identifier);
7223        }
7224
7225        locals.$scope[identifier] = instance;
7226      }
7227
7228      return instance;
7229    };
7230  }];
7231}
7232
7233/**
7234 * @ngdoc service
7235 * @name $document
7236 * @requires $window
7237 *
7238 * @description
7239 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7240 *
7241 * @example
7242   <example>
7243     <file name="index.html">
7244       <div ng-controller="MainCtrl">
7245         <p>$document title: <b ng-bind="title"></b></p>
7246         <p>window.document title: <b ng-bind="windowTitle"></b></p>
7247       </div>
7248     </file>
7249     <file name="script.js">
7250       function MainCtrl($scope, $document) {
7251         $scope.title = $document[0].title;
7252         $scope.windowTitle = angular.element(window.document)[0].title;
7253       }
7254     </file>
7255   </example>
7256 */
7257function $DocumentProvider(){
7258  this.$get = ['$window', function(window){
7259    return jqLite(window.document);
7260  }];
7261}
7262
7263/**
7264 * @ngdoc service
7265 * @name $exceptionHandler
7266 * @requires ng.$log
7267 *
7268 * @description
7269 * Any uncaught exception in angular expressions is delegated to this service.
7270 * The default implementation simply delegates to `$log.error` which logs it into
7271 * the browser console.
7272 *
7273 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7274 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7275 *
7276 * ## Example:
7277 *
7278 * ```js
7279 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7280 *     return function (exception, cause) {
7281 *       exception.message += ' (caused by "' + cause + '")';
7282 *       throw exception;
7283 *     };
7284 *   });
7285 * ```
7286 *
7287 * This example will override the normal action of `$exceptionHandler`, to make angular
7288 * exceptions fail hard when they happen, instead of just logging to the console.
7289 *
7290 * @param {Error} exception Exception associated with the error.
7291 * @param {string=} cause optional information about the context in which
7292 *       the error was thrown.
7293 *
7294 */
7295function $ExceptionHandlerProvider() {
7296  this.$get = ['$log', function($log) {
7297    return function(exception, cause) {
7298      $log.error.apply($log, arguments);
7299    };
7300  }];
7301}
7302
7303/**
7304 * Parse headers into key value object
7305 *
7306 * @param {string} headers Raw headers as a string
7307 * @returns {Object} Parsed headers as key value object
7308 */
7309function parseHeaders(headers) {
7310  var parsed = {}, key, val, i;
7311
7312  if (!headers) return parsed;
7313
7314  forEach(headers.split('\n'), function(line) {
7315    i = line.indexOf(':');
7316    key = lowercase(trim(line.substr(0, i)));
7317    val = trim(line.substr(i + 1));
7318
7319    if (key) {
7320      if (parsed[key]) {
7321        parsed[key] += ', ' + val;
7322      } else {
7323        parsed[key] = val;
7324      }
7325    }
7326  });
7327
7328  return parsed;
7329}
7330
7331
7332/**
7333 * Returns a function that provides access to parsed headers.
7334 *
7335 * Headers are lazy parsed when first requested.
7336 * @see parseHeaders
7337 *
7338 * @param {(string|Object)} headers Headers to provide access to.
7339 * @returns {function(string=)} Returns a getter function which if called with:
7340 *
7341 *   - if called with single an argument returns a single header value or null
7342 *   - if called with no arguments returns an object containing all headers.
7343 */
7344function headersGetter(headers) {
7345  var headersObj = isObject(headers) ? headers : undefined;
7346
7347  return function(name) {
7348    if (!headersObj) headersObj =  parseHeaders(headers);
7349
7350    if (name) {
7351      return headersObj[lowercase(name)] || null;
7352    }
7353
7354    return headersObj;
7355  };
7356}
7357
7358
7359/**
7360 * Chain all given functions
7361 *
7362 * This function is used for both request and response transforming
7363 *
7364 * @param {*} data Data to transform.
7365 * @param {function(string=)} headers Http headers getter fn.
7366 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7367 * @returns {*} Transformed data.
7368 */
7369function transformData(data, headers, fns) {
7370  if (isFunction(fns))
7371    return fns(data, headers);
7372
7373  forEach(fns, function(fn) {
7374    data = fn(data, headers);
7375  });
7376
7377  return data;
7378}
7379
7380
7381function isSuccess(status) {
7382  return 200 <= status && status < 300;
7383}
7384
7385
7386function $HttpProvider() {
7387  var JSON_START = /^\s*(\[|\{[^\{])/,
7388      JSON_END = /[\}\]]\s*$/,
7389      PROTECTION_PREFIX = /^\)\]\}',?\n/,
7390      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7391
7392  var defaults = this.defaults = {
7393    // transform incoming response data
7394    transformResponse: [function(data) {
7395      if (isString(data)) {
7396        // strip json vulnerability protection prefix
7397        data = data.replace(PROTECTION_PREFIX, '');
7398        if (JSON_START.test(data) && JSON_END.test(data))
7399          data = fromJson(data);
7400      }
7401      return data;
7402    }],
7403
7404    // transform outgoing request data
7405    transformRequest: [function(d) {
7406      return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7407    }],
7408
7409    // default headers
7410    headers: {
7411      common: {
7412        'Accept': 'application/json, text/plain, */*'
7413      },
7414      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7415      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7416      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
7417    },
7418
7419    xsrfCookieName: 'XSRF-TOKEN',
7420    xsrfHeaderName: 'X-XSRF-TOKEN'
7421  };
7422
7423  /**
7424   * Are ordered by request, i.e. they are applied in the same order as the
7425   * array, on request, but reverse order, on response.
7426   */
7427  var interceptorFactories = this.interceptors = [];
7428
7429  /**
7430   * For historical reasons, response interceptors are ordered by the order in which
7431   * they are applied to the response. (This is the opposite of interceptorFactories)
7432   */
7433  var responseInterceptorFactories = this.responseInterceptors = [];
7434
7435  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7436      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7437
7438    var defaultCache = $cacheFactory('$http');
7439
7440    /**
7441     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7442     * The reversal is needed so that we can build up the interception chain around the
7443     * server request.
7444     */
7445    var reversedInterceptors = [];
7446
7447    forEach(interceptorFactories, function(interceptorFactory) {
7448      reversedInterceptors.unshift(isString(interceptorFactory)
7449          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7450    });
7451
7452    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7453      var responseFn = isString(interceptorFactory)
7454          ? $injector.get(interceptorFactory)
7455          : $injector.invoke(interceptorFactory);
7456
7457      /**
7458       * Response interceptors go before "around" interceptors (no real reason, just
7459       * had to pick one.) But they are already reversed, so we can't use unshift, hence
7460       * the splice.
7461       */
7462      reversedInterceptors.splice(index, 0, {
7463        response: function(response) {
7464          return responseFn($q.when(response));
7465        },
7466        responseError: function(response) {
7467          return responseFn($q.reject(response));
7468        }
7469      });
7470    });
7471
7472
7473    /**
7474     * @ngdoc service
7475     * @kind function
7476     * @name $http
7477     * @requires ng.$httpBackend
7478     * @requires $cacheFactory
7479     * @requires $rootScope
7480     * @requires $q
7481     * @requires $injector
7482     *
7483     * @description
7484     * The `$http` service is a core Angular service that facilitates communication with the remote
7485     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7486     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7487     *
7488     * For unit testing applications that use `$http` service, see
7489     * {@link ngMock.$httpBackend $httpBackend mock}.
7490     *
7491     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7492     * $resource} service.
7493     *
7494     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7495     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7496     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7497     *
7498     *
7499     * # General usage
7500     * The `$http` service is a function which takes a single argument — a configuration object —
7501     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7502     * with two $http specific methods: `success` and `error`.
7503     *
7504     * ```js
7505     *   $http({method: 'GET', url: '/someUrl'}).
7506     *     success(function(data, status, headers, config) {
7507     *       // this callback will be called asynchronously
7508     *       // when the response is available
7509     *     }).
7510     *     error(function(data, status, headers, config) {
7511     *       // called asynchronously if an error occurs
7512     *       // or server returns response with an error status.
7513     *     });
7514     * ```
7515     *
7516     * Since the returned value of calling the $http function is a `promise`, you can also use
7517     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7518     * an object representing the response. See the API signature and type info below for more
7519     * details.
7520     *
7521     * A response status code between 200 and 299 is considered a success status and
7522     * will result in the success callback being called. Note that if the response is a redirect,
7523     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7524     * called for such responses.
7525     *
7526     * # Writing Unit Tests that use $http
7527     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7528     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7529     * request using trained responses.
7530     *
7531     * ```
7532     * $httpBackend.expectGET(...);
7533     * $http.get(...);
7534     * $httpBackend.flush();
7535     * ```
7536     *
7537     * # Shortcut methods
7538     *
7539     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7540     * request data must be passed in for POST/PUT requests.
7541     *
7542     * ```js
7543     *   $http.get('/someUrl').success(successCallback);
7544     *   $http.post('/someUrl', data).success(successCallback);
7545     * ```
7546     *
7547     * Complete list of shortcut methods:
7548     *
7549     * - {@link ng.$http#get $http.get}
7550     * - {@link ng.$http#head $http.head}
7551     * - {@link ng.$http#post $http.post}
7552     * - {@link ng.$http#put $http.put}
7553     * - {@link ng.$http#delete $http.delete}
7554     * - {@link ng.$http#jsonp $http.jsonp}
7555     *
7556     *
7557     * # Setting HTTP Headers
7558     *
7559     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7560     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7561     * object, which currently contains this default configuration:
7562     *
7563     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7564     *   - `Accept: application/json, text/plain, * / *`
7565     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7566     *   - `Content-Type: application/json`
7567     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7568     *   - `Content-Type: application/json`
7569     *
7570     * To add or overwrite these defaults, simply add or remove a property from these configuration
7571     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7572     * with the lowercased HTTP method name as the key, e.g.
7573     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7574     *
7575     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7576     * fashion. For example:
7577     *
7578     * ```
7579     * module.run(function($http) {
7580     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7581     * });
7582     * ```
7583     *
7584     * In addition, you can supply a `headers` property in the config object passed when
7585     * calling `$http(config)`, which overrides the defaults without changing them globally.
7586     *
7587     *
7588     * # Transforming Requests and Responses
7589     *
7590     * Both requests and responses can be transformed using transform functions. By default, Angular
7591     * applies these transformations:
7592     *
7593     * Request transformations:
7594     *
7595     * - If the `data` property of the request configuration object contains an object, serialize it
7596     *   into JSON format.
7597     *
7598     * Response transformations:
7599     *
7600     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7601     *  - If JSON response is detected, deserialize it using a JSON parser.
7602     *
7603     * To globally augment or override the default transforms, modify the
7604     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7605     * properties. These properties are by default an array of transform functions, which allows you
7606     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7607     * also decide to completely override any default transformations by assigning your
7608     * transformation functions to these properties directly without the array wrapper.  These defaults
7609     * are again available on the $http factory at run-time, which may be useful if you have run-time
7610     * services you wish to be involved in your transformations.
7611     *
7612     * Similarly, to locally override the request/response transforms, augment the
7613     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7614     * into `$http`.
7615     *
7616     *
7617     * # Caching
7618     *
7619     * To enable caching, set the request configuration `cache` property to `true` (to use default
7620     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7621     * When the cache is enabled, `$http` stores the response from the server in the specified
7622     * cache. The next time the same request is made, the response is served from the cache without
7623     * sending a request to the server.
7624     *
7625     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7626     * the same way that real requests are.
7627     *
7628     * If there are multiple GET requests for the same URL that should be cached using the same
7629     * cache, but the cache is not populated yet, only one request to the server will be made and
7630     * the remaining requests will be fulfilled using the response from the first request.
7631     *
7632     * You can change the default cache to a new object (built with
7633     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7634     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7635     * their `cache` property to `true` will now use this cache object.
7636     *
7637     * If you set the default cache to `false` then only requests that specify their own custom
7638     * cache object will be cached.
7639     *
7640     * # Interceptors
7641     *
7642     * Before you start creating interceptors, be sure to understand the
7643     * {@link ng.$q $q and deferred/promise APIs}.
7644     *
7645     * For purposes of global error handling, authentication, or any kind of synchronous or
7646     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7647     * able to intercept requests before they are handed to the server and
7648     * responses before they are handed over to the application code that
7649     * initiated these requests. The interceptors leverage the {@link ng.$q
7650     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7651     *
7652     * The interceptors are service factories that are registered with the `$httpProvider` by
7653     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7654     * injected with dependencies (if specified) and returns the interceptor.
7655     *
7656     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7657     *
7658     *   * `request`: interceptors get called with a http `config` object. The function is free to
7659     *     modify the `config` object or create a new one. The function needs to return the `config`
7660     *     object directly, or a promise containing the `config` or a new `config` object.
7661     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7662     *     resolved with a rejection.
7663     *   * `response`: interceptors get called with http `response` object. The function is free to
7664     *     modify the `response` object or create a new one. The function needs to return the `response`
7665     *     object directly, or as a promise containing the `response` or a new `response` object.
7666     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7667     *     resolved with a rejection.
7668     *
7669     *
7670     * ```js
7671     *   // register the interceptor as a service
7672     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7673     *     return {
7674     *       // optional method
7675     *       'request': function(config) {
7676     *         // do something on success
7677     *         return config;
7678     *       },
7679     *
7680     *       // optional method
7681     *      'requestError': function(rejection) {
7682     *         // do something on error
7683     *         if (canRecover(rejection)) {
7684     *           return responseOrNewPromise
7685     *         }
7686     *         return $q.reject(rejection);
7687     *       },
7688     *
7689     *
7690     *
7691     *       // optional method
7692     *       'response': function(response) {
7693     *         // do something on success
7694     *         return response;
7695     *       },
7696     *
7697     *       // optional method
7698     *      'responseError': function(rejection) {
7699     *         // do something on error
7700     *         if (canRecover(rejection)) {
7701     *           return responseOrNewPromise
7702     *         }
7703     *         return $q.reject(rejection);
7704     *       }
7705     *     };
7706     *   });
7707     *
7708     *   $httpProvider.interceptors.push('myHttpInterceptor');
7709     *
7710     *
7711     *   // alternatively, register the interceptor via an anonymous factory
7712     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7713     *     return {
7714     *      'request': function(config) {
7715     *          // same as above
7716     *       },
7717     *
7718     *       'response': function(response) {
7719     *          // same as above
7720     *       }
7721     *     };
7722     *   });
7723     * ```
7724     *
7725     * # Response interceptors (DEPRECATED)
7726     *
7727     * Before you start creating interceptors, be sure to understand the
7728     * {@link ng.$q $q and deferred/promise APIs}.
7729     *
7730     * For purposes of global error handling, authentication or any kind of synchronous or
7731     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7732     * responses for http requests before they are handed over to the application code that
7733     * initiated these requests. The response interceptors leverage the {@link ng.$q
7734     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7735     *
7736     * The interceptors are service factories that are registered with the $httpProvider by
7737     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7738     * injected with dependencies (if specified) and returns the interceptor  — a function that
7739     * takes a {@link ng.$q promise} and returns the original or a new promise.
7740     *
7741     * ```js
7742     *   // register the interceptor as a service
7743     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7744     *     return function(promise) {
7745     *       return promise.then(function(response) {
7746     *         // do something on success
7747     *         return response;
7748     *       }, function(response) {
7749     *         // do something on error
7750     *         if (canRecover(response)) {
7751     *           return responseOrNewPromise
7752     *         }
7753     *         return $q.reject(response);
7754     *       });
7755     *     }
7756     *   });
7757     *
7758     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7759     *
7760     *
7761     *   // register the interceptor via an anonymous factory
7762     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7763     *     return function(promise) {
7764     *       // same as above
7765     *     }
7766     *   });
7767     * ```
7768     *
7769     *
7770     * # Security Considerations
7771     *
7772     * When designing web applications, consider security threats from:
7773     *
7774     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7775     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7776     *
7777     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7778     * pre-configured with strategies that address these issues, but for this to work backend server
7779     * cooperation is required.
7780     *
7781     * ## JSON Vulnerability Protection
7782     *
7783     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7784     * allows third party website to turn your JSON resource URL into
7785     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7786     * counter this your server can prefix all JSON requests with following str
7786ing `")]}',\n"`.
7787     * Angular will automatically strip the prefix before processing it as JSON.
7788     *
7789     * For example if your server needs to return:
7790     * ```js
7791     * ['one','two']
7792     * ```
7793     *
7794     * which is vulnerable to attack, your server can return:
7795     * ```js
7796     * )]}',
7797     * ['one','two']
7798     * ```
7799     *
7800     * Angular will strip the prefix, before processing the JSON.
7801     *
7802     *
7803     * ## Cross Site Request Forgery (XSRF) Protection
7804     *
7805     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7806     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7807     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7808     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7809     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7810     * the XHR came from JavaScript running on your domain. The header will not be set for
7811     * cross-domain requests.
7812     *
7813     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7814     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7815     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7816     * that only JavaScript running on your domain could have sent the request. The token must be
7817     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7818     * making up its own tokens). We recommend that the token is a digest of your site's
7819     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
7820     * for added security.
7821     *
7822     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7823     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7824     * or the per-request config object.
7825     *
7826     *
7827     * @param {object} config Object describing the request to be made and how it should be
7828     *    processed. The object has following properties:
7829     *
7830     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7831     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7832     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7833     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7834     *      JSONified.
7835     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7836     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7837     *      HTTP headers to send to the server. If the return value of a function is null, the
7838     *      header will not be sent.
7839     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7840     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7841     *    - **transformRequest** –
7842     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7843     *      transform function or an array of such functions. The transform function takes the http
7844     *      request body and headers and returns its transformed (typically serialized) version.
7845     *    - **transformResponse** –
7846     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7847     *      transform function or an array of such functions. The transform function takes the http
7848     *      response body and headers and returns its transformed (typically deserialized) version.
7849     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7850     *      GET request, otherwise if a cache instance built with
7851     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7852     *      caching.
7853     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7854     *      that should abort the request when resolved.
7855     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
7856     *      XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5
7857     *      for more information.
7858     *    - **responseType** - `{string}` - see
7859     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
7860     *
7861     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7862     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7863     *   method takes two arguments a success and an error callback which will be called with a
7864     *   response object. The `success` and `error` methods take a single argument - a function that
7865     *   will be called when the request succeeds or fails respectively. The arguments passed into
7866     *   these functions are destructured representation of the response object passed into the
7867     *   `then` method. The response object has these properties:
7868     *
7869     *   - **data** – `{string|Object}` – The response body transformed with the transform
7870     *     functions.
7871     *   - **status** – `{number}` – HTTP status code of the response.
7872     *   - **headers** – `{function([headerName])}` – Header getter function.
7873     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7874     *   - **statusText** – `{string}` – HTTP status text of the response.
7875     *
7876     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7877     *   requests. This is primarily meant to be used for debugging purposes.
7878     *
7879     *
7880     * @example
7881<example>
7882<file name="index.html">
7883  <div ng-controller="FetchCtrl">
7884    <select ng-model="method">
7885      <option>GET</option>
7886      <option>JSONP</option>
7887    </select>
7888    <input type="text" ng-model="url" size="80"/>
7889    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7890    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7891    <button id="samplejsonpbtn"
7892      ng-click="updateModel('JSONP',
7893                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7894      Sample JSONP
7895    </button>
7896    <button id="invalidjsonpbtn"
7897      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7898        Invalid JSONP
7899      </button>
7900    <pre>http status code: {{status}}</pre>
7901    <pre>http response data: {{data}}</pre>
7902  </div>
7903</file>
7904<file name="script.js">
7905  function FetchCtrl($scope, $http, $templateCache) {
7906    $scope.method = 'GET';
7907    $scope.url = 'http-hello.html';
7908
7909    $scope.fetch = function() {
7910      $scope.code = null;
7911      $scope.response = null;
7912
7913      $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7914        success(function(data, status) {
7915          $scope.status = status;
7916          $scope.data = data;
7917        }).
7918        error(function(data, status) {
7919          $scope.data = data || "Request failed";
7920          $scope.status = status;
7921      });
7922    };
7923
7924    $scope.updateModel = function(method, url) {
7925      $scope.method = method;
7926      $scope.url = url;
7927    };
7928  }
7929</file>
7930<file name="http-hello.html">
7931  Hello, $http!
7932</file>
7933<file name="protractor.js" type="protractor">
7934  var status = element(by.binding('status'));
7935  var data = element(by.binding('data'));
7936  var fetchBtn = element(by.id('fetchbtn'));
7937  var sampleGetBtn = element(by.id('samplegetbtn'));
7938  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
7939  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
7940
7941  it('should make an xhr GET request', function() {
7942    sampleGetBtn.click();
7943    fetchBtn.click();
7944    expect(status.getText()).toMatch('200');
7945    expect(data.getText()).toMatch(/Hello, \$http!/);
7946  });
7947
7948  it('should make a JSONP request to angularjs.org', function() {
7949    sampleJsonpBtn.click();
7950    fetchBtn.click();
7951    expect(status.getText()).toMatch('200');
7952    expect(data.getText()).toMatch(/Super Hero!/);
7953  });
7954
7955  it('should make JSONP request to invalid URL and invoke the error handler',
7956      function() {
7957    invalidJsonpBtn.click();
7958    fetchBtn.click();
7959    expect(status.getText()).toMatch('0');
7960    expect(data.getText()).toMatch('Request failed');
7961  });
7962</file>
7963</example>
7964     */
7965    function $http(requestConfig) {
7966      var config = {
7967        method: 'get',
7968        transformRequest: defaults.transformRequest,
7969        transformResponse: defaults.transformResponse
7970      };
7971      var headers = mergeHeaders(requestConfig);
7972
7973      extend(config, requestConfig);
7974      config.headers = headers;
7975      config.method = uppercase(config.method);
7976
7977      var serverRequest = function(config) {
7978        headers = config.headers;
7979        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
7980
7981        // strip content-type if data is undefined
7982        if (isUndefined(config.data)) {
7983          forEach(headers, function(value, header) {
7984            if (lowercase(header) === 'content-type') {
7985                delete headers[header];
7986            }
7987          });
7988        }
7989
7990        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
7991          config.withCredentials = defaults.withCredentials;
7992        }
7993
7994        // send request
7995        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
7996      };
7997
7998      var chain = [serverRequest, undefined];
7999      var promise = $q.when(config);
8000
8001      // apply interceptors
8002      forEach(reversedInterceptors, function(interceptor) {
8003        if (interceptor.request || interceptor.requestError) {
8004          chain.unshift(interceptor.request, interceptor.requestError);
8005        }
8006        if (interceptor.response || interceptor.responseError) {
8007          chain.push(interceptor.response, interceptor.responseError);
8008        }
8009      });
8010
8011      while(chain.length) {
8012        var thenFn = chain.shift();
8013        var rejectFn = chain.shift();
8014
8015        promise = promise.then(thenFn, rejectFn);
8016      }
8017
8018      promise.success = function(fn) {
8019        promise.then(function(response) {
8020          fn(response.data, response.status, response.headers, config);
8021        });
8022        return promise;
8023      };
8024
8025      promise.error = function(fn) {
8026        promise.then(null, function(response) {
8027          fn(response.data, response.status, response.headers, config);
8028        });
8029        return promise;
8030      };
8031
8032      return promise;
8033
8034      function transformResponse(response) {
8035        // make a copy since the response must be cacheable
8036        var resp = extend({}, response, {
8037          data: transformData(response.data, response.headers, config.transformResponse)
8038        });
8039        return (isSuccess(response.status))
8040          ? resp
8041          : $q.reject(resp);
8042      }
8043
8044      function mergeHeaders(config) {
8045        var defHeaders = defaults.headers,
8046            reqHeaders = extend({}, config.headers),
8047            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
8048
8049        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
8050
8051        // execute if header value is function
8052        execHeaders(defHeaders);
8053        execHeaders(reqHeaders);
8054
8055        // using for-in instead of forEach to avoid unecessary iteration after header has been found
8056        defaultHeadersIteration:
8057        for (defHeaderName in defHeaders) {
8058          lowercaseDefHeaderName = lowercase(defHeaderName);
8059
8060          for (reqHeaderName in reqHeaders) {
8061            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
8062              continue defaultHeadersIteration;
8063            }
8064          }
8065
8066          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
8067        }
8068
8069        return reqHeaders;
8070
8071        function execHeaders(headers) {
8072          var headerContent;
8073
8074          forEach(headers, function(headerFn, header) {
8075            if (isFunction(headerFn)) {
8076              headerContent = headerFn();
8077              if (headerContent != null) {
8078                headers[header] = headerContent;
8079              } else {
8080                delete headers[header];
8081              }
8082            }
8083          });
8084        }
8085      }
8086    }
8087
8088    $http.pendingRequests = [];
8089
8090    /**
8091     * @ngdoc method
8092     * @name $http#get
8093     *
8094     * @description
8095     * Shortcut method to perform `GET` request.
8096     *
8097     * @param {string} url Relative or absolute URL specifying the destination of the request
8098     * @param {Object=} config Optional configuration object
8099     * @returns {HttpPromise} Future object
8100     */
8101
8102    /**
8103     * @ngdoc method
8104     * @name $http#delete
8105     *
8106     * @description
8107     * Shortcut method to perform `DELETE` request.
8108     *
8109     * @param {string} url Relative or absolute URL specifying the destination of the request
8110     * @param {Object=} config Optional configuration object
8111     * @returns {HttpPromise} Future object
8112     */
8113
8114    /**
8115     * @ngdoc method
8116     * @name $http#head
8117     *
8118     * @description
8119     * Shortcut method to perform `HEAD` request.
8120     *
8121     * @param {string} url Relative or absolute URL specifying the destination of the request
8122     * @param {Object=} config Optional configuration object
8123     * @returns {HttpPromise} Future object
8124     */
8125
8126    /**
8127     * @ngdoc method
8128     * @name $http#jsonp
8129     *
8130     * @description
8131     * Shortcut method to perform `JSONP` request.
8132     *
8133     * @param {string} url Relative or absolute URL specifying the destination of the request.
8134     *                     Should contain `JSON_CALLBACK` string.
8135     * @param {Object=} config Optional configuration object
8136     * @returns {HttpPromise} Future object
8137     */
8138    createShortMethods('get', 'delete', 'head', 'jsonp');
8139
8140    /**
8141     * @ngdoc method
8142     * @name $http#post
8143     *
8144     * @description
8145     * Shortcut method to perform `POST` request.
8146     *
8147     * @param {string} url Relative or absolute URL specifying the destination of the request
8148     * @param {*} data Request content
8149     * @param {Object=} config Optional configuration object
8150     * @returns {HttpPromise} Future object
8151     */
8152
8153    /**
8154     * @ngdoc method
8155     * @name $http#put
8156     *
8157     * @description
8158     * Shortcut method to perform `PUT` request.
8159     *
8160     * @param {string} url Relative or absolute URL specifying the destination of the request
8161     * @param {*} data Request content
8162     * @param {Object=} config Optional configuration object
8163     * @returns {HttpPromise} Future object
8164     */
8165    createShortMethodsWithData('post', 'put');
8166
8167        /**
8168         * @ngdoc property
8169         * @name $http#defaults
8170         *
8171         * @description
8172         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8173         * default headers, withCredentials as well as request and response transformations.
8174         *
8175         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8176         */
8177    $http.defaults = defaults;
8178
8179
8180    return $http;
8181
8182
8183    function createShortMethods(names) {
8184      forEach(arguments, function(name) {
8185        $http[name] = function(url, config) {
8186          return $http(extend(config || {}, {
8187            method: name,
8188            url: url
8189          }));
8190        };
8191      });
8192    }
8193
8194
8195    function createShortMethodsWithData(name) {
8196      forEach(arguments, function(name) {
8197        $http[name] = function(url, data, config) {
8198          return $http(extend(config || {}, {
8199            method: name,
8200            url: url,
8201            data: data
8202          }));
8203        };
8204      });
8205    }
8206
8207
8208    /**
8209     * Makes the request.
8210     *
8211     * !!! ACCESSES CLOSURE VARS:
8212     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8213     */
8214    function sendReq(config, reqData, reqHeaders) {
8215      var deferred = $q.defer(),
8216          promise = deferred.promise,
8217          cache,
8218          cachedResp,
8219          url = buildUrl(config.url, config.params);
8220
8221      $http.pendingRequests.push(config);
8222      promise.then(removePendingReq, removePendingReq);
8223
8224
8225      if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
8226        cache = isObject(config.cache) ? config.cache
8227              : isObject(defaults.cache) ? defaults.cache
8228              : defaultCache;
8229      }
8230
8231      if (cache) {
8232        cachedResp = cache.get(url);
8233        if (isDefined(cachedResp)) {
8234          if (cachedResp.then) {
8235            // cached request has already been sent, but there is no response yet
8236            cachedResp.then(removePendingReq, removePendingReq);
8237            return cachedResp;
8238          } else {
8239            // serving from cache
8240            if (isArray(cachedResp)) {
8241              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
8242            } else {
8243              resolvePromise(cachedResp, 200, {}, 'OK');
8244            }
8245          }
8246        } else {
8247          // put the promise for the non-transformed response into cache as a placeholder
8248          cache.put(url, promise);
8249        }
8250      }
8251
8252
8253      // if we won't have the response in cache, set the xsrf headers and
8254      // send the request to the backend
8255      if (isUndefined(cachedResp)) {
8256        var xsrfValue = urlIsSameOrigin(config.url)
8257            ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
8258            : undefined;
8259        if (xsrfValue) {
8260          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
8261        }
8262
8263        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8264            config.withCredentials, config.responseType);
8265      }
8266
8267      return promise;
8268
8269
8270      /**
8271       * Callback registered to $httpBackend():
8272       *  - caches the response if desired
8273       *  - resolves the raw $http promise
8274       *  - calls $apply
8275       */
8276      function done(status, response, headersString, statusText) {
8277        if (cache) {
8278          if (isSuccess(status)) {
8279            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8280          } else {
8281            // remove promise from the cache
8282            cache.remove(url);
8283          }
8284        }
8285
8286        resolvePromise(response, status, headersString, statusText);
8287        if (!$rootScope.$$phase) $rootScope.$apply();
8288      }
8289
8290
8291      /**
8292       * Resolves the raw $http promise.
8293       */
8294      function resolvePromise(response, status, headers, statusText) {
8295        // normalize internal statuses to 0
8296        status = Math.max(status, 0);
8297
8298        (isSuccess(status) ? deferred.resolve : deferred.reject)({
8299          data: response,
8300          status: status,
8301          headers: headersGetter(headers),
8302          config: config,
8303          statusText : statusText
8304        });
8305      }
8306
8307
8308      function removePendingReq() {
8309        var idx = indexOf($http.pendingRequests, config);
8310        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8311      }
8312    }
8313
8314
8315    function buildUrl(url, params) {
8316          if (!params) return url;
8317          var parts = [];
8318          forEachSorted(params, function(value, key) {
8319            if (value === null || isUndefined(value)) return;
8320            if (!isArray(value)) value = [value];
8321
8322            forEach(value, function(v) {
8323              if (isObject(v)) {
8324                v = toJson(v);
8325              }
8326              parts.push(encodeUriQuery(key) + '=' +
8327                         encodeUriQuery(v));
8328            });
8329          });
8330          if(parts.length > 0) {
8331            url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8332          }
8333          return url;
8334        }
8335
8336
8337  }];
8338}
8339
8340function createXhr(method) {
8341    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8342    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8343    //if it is available
8344    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
8345      !window.XMLHttpRequest)) {
8346      return new window.ActiveXObject("Microsoft.XMLHTTP");
8347    } else if (window.XMLHttpRequest) {
8348      return new window.XMLHttpRequest();
8349    }
8350
8351    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8352}
8353
8354/**
8355 * @ngdoc service
8356 * @name $httpBackend
8357 * @requires $window
8358 * @requires $document
8359 *
8360 * @description
8361 * HTTP backend used by the {@link ng.$http service} that delegates to
8362 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8363 *
8364 * You should never need to use this service directly, instead use the higher-level abstractions:
8365 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8366 *
8367 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8368 * $httpBackend} which can be trained with responses.
8369 */
8370function $HttpBackendProvider() {
8371  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
8372    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8373  }];
8374}
8375
8376function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8377  var ABORTED = -1;
8378
8379  // TODO(vojta): fix the signature
8380  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8381    var status;
8382    $browser.$$incOutstandingRequestCount();
8383    url = url || $browser.url();
8384
8385    if (lowercase(method) == 'jsonp') {
8386      var callbackId = '_' + (callbacks.counter++).toString(36);
8387      callbacks[callbackId] = function(data) {
8388        callbacks[callbackId].data = data;
8389        callbacks[callbackId].called = true;
8390      };
8391
8392      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8393          callbackId, function(status, text) {
8394        completeRequest(callback, status, callbacks[callbackId].data, "", text);
8395        callbacks[callbackId] = noop;
8396      });
8397    } else {
8398
8399      var xhr = createXhr(method);
8400
8401      xhr.open(method, url, true);
8402      forEach(headers, function(value, key) {
8403        if (isDefined(value)) {
8404            xhr.setRequestHeader(key, value);
8405        }
8406      });
8407
8408      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8409      // response is in the cache. the promise api will ensure that to the app code the api is
8410      // always async
8411      xhr.onreadystatechange = function() {
8412        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8413        // xhrs that are resolved while the app is in the background (see #5426).
8414        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8415        // continuing
8416        //
8417        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8418        // Safari respectively.
8419        if (xhr && xhr.readyState == 4) {
8420          var responseHeaders = null,
8421              response = null,
8422              statusText = '';
8423
8424          if(status !== ABORTED) {
8425            responseHeaders = xhr.getAllResponseHeaders();
8426
8427            // responseText is the old-school way of retrieving response 
8427(supported by IE8 & 9)
8428            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8429            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8430          }
8431
8432          // Accessing statusText on an aborted xhr object will
8433          // throw an 'c00c023f error' in IE9 and lower, don't touch it.
8434          if (!(status === ABORTED && msie < 10)) {
8435            statusText = xhr.statusText;
8436          }
8437
8438          completeRequest(callback,
8439              status || xhr.status,
8440              response,
8441              responseHeaders,
8442              statusText);
8443        }
8444      };
8445
8446      if (withCredentials) {
8447        xhr.withCredentials = true;
8448      }
8449
8450      if (responseType) {
8451        try {
8452          xhr.responseType = responseType;
8453        } catch (e) {
8454          // WebKit added support for the json responseType value on 09/03/2013
8455          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8456          // known to throw when setting the value "json" as the response type. Other older
8457          // browsers implementing the responseType
8458          //
8459          // The json response type can be ignored if not supported, because JSON payloads are
8460          // parsed on the client-side regardless.
8461          if (responseType !== 'json') {
8462            throw e;
8463          }
8464        }
8465      }
8466
8467      xhr.send(post || null);
8468    }
8469
8470    if (timeout > 0) {
8471      var timeoutId = $browserDefer(timeoutRequest, timeout);
8472    } else if (timeout && timeout.then) {
8473      timeout.then(timeoutRequest);
8474    }
8475
8476
8477    function timeoutRequest() {
8478      status = ABORTED;
8479      jsonpDone && jsonpDone();
8480      xhr && xhr.abort();
8481    }
8482
8483    function completeRequest(callback, status, response, headersString, statusText) {
8484      // cancel timeout and subsequent timeout promise resolution
8485      timeoutId && $browserDefer.cancel(timeoutId);
8486      jsonpDone = xhr = null;
8487
8488      // fix status code when it is 0 (0 status is undocumented).
8489      // Occurs when accessing file resources or on Android 4.1 stock browser
8490      // while retrieving files from application cache.
8491      if (status === 0) {
8492        status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8493      }
8494
8495      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8496      status = status === 1223 ? 204 : status;
8497      statusText = statusText || '';
8498
8499      callback(status, response, headersString, statusText);
8500      $browser.$$completeOutstandingRequest(noop);
8501    }
8502  };
8503
8504  function jsonpReq(url, callbackId, done) {
8505    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8506    // - fetches local scripts via XHR and evals them
8507    // - adds and immediately removes script elements from the document
8508    var script = rawDocument.createElement('script'), callback = null;
8509    script.type = "text/javascript";
8510    script.src = url;
8511    script.async = true;
8512
8513    callback = function(event) {
8514      removeEventListenerFn(script, "load", callback);
8515      removeEventListenerFn(script, "error", callback);
8516      rawDocument.body.removeChild(script);
8517      script = null;
8518      var status = -1;
8519      var text = "unknown";
8520
8521      if (event) {
8522        if (event.type === "load" && !callbacks[callbackId].called) {
8523          event = { type: "error" };
8524        }
8525        text = event.type;
8526        status = event.type === "error" ? 404 : 200;
8527      }
8528
8529      if (done) {
8530        done(status, text);
8531      }
8532    };
8533
8534    addEventListenerFn(script, "load", callback);
8535    addEventListenerFn(script, "error", callback);
8536
8537    if (msie <= 8) {
8538      script.onreadystatechange = function() {
8539        if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
8540          script.onreadystatechange = null;
8541          callback({
8542            type: 'load'
8543          });
8544        }
8545      };
8546    }
8547
8548    rawDocument.body.appendChild(script);
8549    return callback;
8550  }
8551}
8552
8553var $interpolateMinErr = minErr('$interpolate');
8554
8555/**
8556 * @ngdoc provider
8557 * @name $interpolateProvider
8558 * @kind function
8559 *
8560 * @description
8561 *
8562 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8563 *
8564 * @example
8565<example module="customInterpolationApp">
8566<file name="index.html">
8567<script>
8568  var customInterpolationApp = angular.module('customInterpolationApp', []);
8569
8570  customInterpolationApp.config(function($interpolateProvider) {
8571    $interpolateProvider.startSymbol('//');
8572    $interpolateProvider.endSymbol('//');
8573  });
8574
8575
8576  customInterpolationApp.controller('DemoController', function() {
8577      this.label = "This binding is brought you by // interpolation symbols.";
8578  });
8579</script>
8580<div ng-app="App" ng-controller="DemoController as demo">
8581    //demo.label//
8582</div>
8583</file>
8584<file name="protractor.js" type="protractor">
8585  it('should interpolate binding with custom symbols', function() {
8586    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8587  });
8588</file>
8589</example>
8590 */
8591function $InterpolateProvider() {
8592  var startSymbol = '{{';
8593  var endSymbol = '}}';
8594
8595  /**
8596   * @ngdoc method
8597   * @name $interpolateProvider#startSymbol
8598   * @description
8599   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8600   *
8601   * @param {string=} value new value to set the starting symbol to.
8602   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8603   */
8604  this.startSymbol = function(value){
8605    if (value) {
8606      startSymbol = value;
8607      return this;
8608    } else {
8609      return startSymbol;
8610    }
8611  };
8612
8613  /**
8614   * @ngdoc method
8615   * @name $interpolateProvider#endSymbol
8616   * @description
8617   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8618   *
8619   * @param {string=} value new value to set the ending symbol to.
8620   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8621   */
8622  this.endSymbol = function(value){
8623    if (value) {
8624      endSymbol = value;
8625      return this;
8626    } else {
8627      return endSymbol;
8628    }
8629  };
8630
8631
8632  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8633    var startSymbolLength = startSymbol.length,
8634        endSymbolLength = endSymbol.length;
8635
8636    /**
8637     * @ngdoc service
8638     * @name $interpolate
8639     * @kind function
8640     *
8641     * @requires $parse
8642     * @requires $sce
8643     *
8644     * @description
8645     *
8646     * Compiles a string with markup into an interpolation function. This service is used by the
8647     * HTML {@link ng.$compile $compile} service for data binding. See
8648     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8649     * interpolation markup.
8650     *
8651     *
8652     * ```js
8653     *   var $interpolate = ...; // injected
8654     *   var exp = $interpolate('Hello {{name | uppercase}}!');
8655     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8656     * ```
8657     *
8658     *
8659     * @param {string} text The text with markup to interpolate.
8660     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8661     *    embedded expression in order to return an interpolation function. Strings with no
8662     *    embedded expression will return null for the interpolation function.
8663     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8664     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8665     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8666     *    provides Strict Contextual Escaping for details.
8667     * @returns {function(context)} an interpolation function which is used to compute the
8668     *    interpolated string. The function has these parameters:
8669     *
8670     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8671     *      against.
8672     *
8673     */
8674    function $interpolate(text, mustHaveExpression, trustedContext) {
8675      var startIndex,
8676          endIndex,
8677          index = 0,
8678          parts = [],
8679          length = text.length,
8680          hasInterpolation = false,
8681          fn,
8682          exp,
8683          concat = [];
8684
8685      while(index < length) {
8686        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8687             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8688          (index != startIndex) && parts.push(text.substring(index, startIndex));
8689          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8690          fn.exp = exp;
8691          index = endIndex + endSymbolLength;
8692          hasInterpolation = true;
8693        } else {
8694          // we did not find anything, so we have to add the remainder to the parts array
8695          (index != length) && parts.push(text.substring(index));
8696          index = length;
8697        }
8698      }
8699
8700      if (!(length = parts.length)) {
8701        // we added, nothing, must have been an empty string.
8702        parts.push('');
8703        length = 1;
8704      }
8705
8706      // Concatenating expressions makes it hard to reason about whether some combination of
8707      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8708      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8709      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8710      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8711      // the load when auditing for XSS issues.
8712      if (trustedContext && parts.length > 1) {
8713          throw $interpolateMinErr('noconcat',
8714              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8715              "interpolations that concatenate multiple expressions when a trusted value is " +
8716              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8717      }
8718
8719      if (!mustHaveExpression  || hasInterpolation) {
8720        concat.length = length;
8721        fn = function(context) {
8722          try {
8723            for(var i = 0, ii = length, part; i<ii; i++) {
8724              if (typeof (part = parts[i]) == 'function') {
8725                part = part(context);
8726                if (trustedContext) {
8727                  part = $sce.getTrusted(trustedContext, part);
8728                } else {
8729                  part = $sce.valueOf(part);
8730                }
8731                if (part == null) { // null || undefined
8732                  part = '';
8733                } else {
8734                  switch (typeof part) {
8735                    case 'string':
8736                    {
8737                      break;
8738                    }
8739                    case 'number':
8740                    {
8741                      part = '' + part;
8742                      break;
8743                    }
8744                    default:
8745                    {
8746                      part = toJson(part);
8747                    }
8748                  }
8749                }
8750              }
8751              concat[i] = part;
8752            }
8753            return concat.join('');
8754          }
8755          catch(err) {
8756            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8757                err.toString());
8758            $exceptionHandler(newErr);
8759          }
8760        };
8761        fn.exp = text;
8762        fn.parts = parts;
8763        return fn;
8764      }
8765    }
8766
8767
8768    /**
8769     * @ngdoc method
8770     * @name $interpolate#startSymbol
8771     * @description
8772     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8773     *
8774     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8775     * the symbol.
8776     *
8777     * @returns {string} start symbol.
8778     */
8779    $interpolate.startSymbol = function() {
8780      return startSymbol;
8781    };
8782
8783
8784    /**
8785     * @ngdoc method
8786     * @name $interpolate#endSymbol
8787     * @description
8788     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8789     *
8790     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8791     * the symbol.
8792     *
8793     * @returns {string} end symbol.
8794     */
8795    $interpolate.endSymbol = function() {
8796      return endSymbol;
8797    };
8798
8799    return $interpolate;
8800  }];
8801}
8802
8803function $IntervalProvider() {
8804  this.$get = ['$rootScope', '$window', '$q',
8805       function($rootScope,   $window,   $q) {
8806    var intervals = {};
8807
8808
8809     /**
8810      * @ngdoc service
8811      * @name $interval
8812      *
8813      * @description
8814      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8815      * milliseconds.
8816      *
8817      * The return value of registering an interval function is a promise. This promise will be
8818      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8819      * run indefinitely if `count` is not defined. The value of the notification will be the
8820      * number of iterations that have run.
8821      * To cancel an interval, call `$interval.cancel(promise)`.
8822      *
8823      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
8824      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8825      * time.
8826      *
8827      * <div class="alert alert-warning">
8828      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8829      * with them.  In particular they are not automatically destroyed when a controller's scope or a
8830      * directive's element are destroyed.
8831      * You should take this into consideration and make sure to always cancel the interval at the
8832      * appropriate moment.  See the example below for more details on how and when to do this.
8833      * </div>
8834      *
8835      * @param {function()} fn A function that should be called repeatedly.
8836      * @param {number} delay Number of milliseconds between each function call.
8837      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8838      *   indefinitely.
8839      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8840      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
8841      * @returns {promise} A promise which will be notified on each iteration.
8842      *
8843      * @example
8844      * <example module="time">
8845      *   <file name="index.html">
8846      *     <script>
8847      *       function Ctrl2($scope,$interval) {
8848      *         $scope.format = 'M/d/yy h:mm:ss a';
8849      *         $scope.blood_1 = 100;
8850      *         $scope.blood_2 = 120;
8851      *
8852      *         var stop;
8853      *         $scope.fight = function() {
8854      *           // Don't start a new fight if we are already fighting
8855      *           if ( angular.isDefined(stop) ) return;
8856      *
8857      *           stop = $interval(function() {
8858      *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8859      *                 $scope.blood_1 = $scope.blood_1 - 3;
8860      *                 $scope.blood_2 = $scope.blood_2 - 4;
8861      *             } else {
8862      *                 $scope.stopFight();
8863      *             }
8864      *           }, 100);
8865      *         };
8866      *
8867      *         $scope.stopFight = function() {
8868      *           if (angular.isDefined(stop)) {
8869      *             $interval.cancel(stop);
8870      *             stop = undefined;
8871      *           }
8872      *         };
8873      *
8874      *         $scope.resetFight = function() {
8875      *           $scope.blood_1 = 100;
8876      *           $scope.blood_2 = 120;
8877      *         }
8878      *
8879      *         $scope.$on('$destroy', function() {
8880      *           // Make sure that the interval is destroyed too
8881      *           $scope.stopFight();
8882      *         });
8883      *       }
8884      *
8885      *       angular.module('time', [])
8886      *         // Register the 'myCurrentTime' directive factory method.
8887      *         // We inject $interval and dateFilter service since the factory method is DI.
8888      *         .directive('myCurrentTime', function($interval, dateFilter) {
8889      *           // return the directive link function. (compile function not needed)
8890      *           return function(scope, element, attrs) {
8891      *             var format,  // date format
8892      *             stopTime; // so that we can cancel the time updates
8893      *
8894      *             // used to update the UI
8895      *             function updateTime() {
8896      *               element.text(dateFilter(new Date(), format));
8897      *             }
8898      *
8899      *             // watch the expression, and update the UI on change.
8900      *             scope.$watch(attrs.myCurrentTime, function(value) {
8901      *               format = value;
8902      *               updateTime();
8903      *             });
8904      *
8905      *             stopTime = $interval(updateTime, 1000);
8906      *
8907      *             // listen on DOM destroy (removal) event, and cancel the next UI update
8908      *             // to prevent updating time ofter the DOM element was removed.
8909      *             element.bind('$destroy', function() {
8910      *               $interval.cancel(stopTime);
8911      *             });
8912      *           }
8913      *         });
8914      *     </script>
8915      *
8916      *     <div>
8917      *       <div ng-controller="Ctrl2">
8918      *         Date format: <input ng-model="format"> <hr/>
8919      *         Current time is: <span my-current-time="format"></span>
8920      *         <hr/>
8921      *         Blood 1 : <font color='red'>{{blood_1}}</font>
8922      *         Blood 2 : <font color='red'>{{blood_2}}</font>
8923      *         <button type="button" data-ng-click="fight()">Fight</button>
8924      *         <button type="button" data-ng-click="stopFight()">StopFight</button>
8925      *         <button type="button" data-ng-click="resetFight()">resetFight</button>
8926      *       </div>
8927      *     </div>
8928      *
8929      *   </file>
8930      * </example>
8931      */
8932    function interval(fn, delay, count, invokeApply) {
8933      var setInterval = $window.setInterval,
8934          clearInterval = $window.clearInterval,
8935          deferred = $q.defer(),
8936          promise = deferred.promise,
8937          iteration = 0,
8938          skipApply = (isDefined(invokeApply) && !invokeApply);
8939
8940      count = isDefined(count) ? count : 0;
8941
8942      promise.then(null, null, fn);
8943
8944      promise.$$intervalId = setInterval(function tick() {
8945        deferred.notify(iteration++);
8946
8947        if (count > 0 && iteration >= count) {
8948          deferred.resolve(iteration);
8949          clearInterval(promise.$$intervalId);
8950          delete intervals[promise.$$intervalId];
8951        }
8952
8953        if (!skipApply) $rootScope.$apply();
8954
8955      }, delay);
8956
8957      intervals[promise.$$intervalId] = deferred;
8958
8959      return promise;
8960    }
8961
8962
8963     /**
8964      * @ngdoc method
8965      * @name $interval#cancel
8966      *
8967      * @description
8968      * Cancels a task associated with the `promise`.
8969      *
8970      * @param {promise} promise returned by the `$interval` function.
8971      * @returns {boolean} Returns `true` if the task was successfully canceled.
8972      */
8973    interval.cancel = function(promise) {
8974      if (promise && promise.$$intervalId in intervals) {
8975        intervals[promise.$$intervalId].reject('canceled');
8976        $window.clearInterval(promise.$$intervalId);
8977        delete intervals[promise.$$intervalId];
8978        return true;
8979      }
8980      return false;
8981    };
8982
8983    return interval;
8984  }];
8985}
8986
8987/**
8988 * @ngdoc service
8989 * @name $locale
8990 *
8991 * @description
8992 * $locale service provides localization rules for various Angular components. As of right now the
8993 * only public api is:
8994 *
8995 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
8996 */
8997function $LocaleProvider(){
8998  this.$get = function() {
8999    return {
9000      id: 'en-us',
9001
9002      NUMBER_FORMATS: {
9003        DECIMAL_SEP: '.',
9004        GROUP_SEP: ',',
9005        PATTERNS: [
9006          { // Decimal Pattern
9007            minInt: 1,
9008            minFrac: 0,
9009            maxFrac: 3,
9010            posPre: '',
9011            posSuf: '',
9012            negPre: '-',
9013            negSuf: '',
9014            gSize: 3,
9015            lgSize: 3
9016          },{ //Currency Pattern
9017            minInt: 1,
9018            minFrac: 2,
9019            maxFrac: 2,
9020            posPre: '\u00A4',
9021            posSuf: '',
9022            negPre: '(\u00A4',
9023            negSuf: ')',
9024            gSize: 3,
9025            lgSize: 3
9026          }
9027        ],
9028        CURRENCY_SYM: '$'
9029      },
9030
9031      DATETIME_FORMATS: {
9032        MONTH:
9033            'January,February,March,April,May,June,July,August,September,October,November,December'
9034            .split(','),
9035        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
9036        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
9037        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
9038        AMPMS: ['AM','PM'],
9039        medium: 'MMM d, y h:mm:ss a',
9040        short: 'M/d/yy h:mm a',
9041        fullDate: 'EEEE, MMMM d, y',
9042        longDate: 'MMMM d, y',
9043        mediumDate: 'MMM d, y',
9044        shortDate: 'M/d/yy',
9045        mediumTime: 'h:mm:ss a',
9046        shortTime: 'h:mm a'
9047      },
9048
9049      pluralCat: function(num) {
9050        if (num === 1) {
9051          return 'one';
9052        }
9053        return 'other';
9054      }
9055    };
9056  };
9057}
9058
9059var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
9060    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
9061var $locationMinErr = minErr('$location');
9062
9063
9064/**
9065 * Encode path using encodeUriSegment, ignoring forward slashes
9066 *
9067 * @param {string} path Path to encode
9068 * @returns {string}
9069 */
9070function encodePath(path) {
9071  var segments = path.split('/'),
9072      i = segments.length;
9073
9074  while (i--) {
9075    segments[i] = encodeUriSegment(segments[i]);
9076  }
9077
9078  return segments.join('/');
9079}
9080
9081function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
9082  var parsedUrl = urlResolve(absoluteUrl, appBase);
9083
9084  locationObj.$$protocol = parsedUrl.protocol;
9085  locationObj.$$host = parsedUrl.hostname;
9086  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
9087}
9088
9089
9090function parseAppUrl(relativeUrl, locationObj, appBase) {
9091  var prefixed = (relativeUrl.charAt(0) !== '/');
9092  if (prefixed) {
9093    relativeUrl = '/' + relativeUrl;
9094  }
9095  var match = urlResolve(relativeUrl, appBase);
9096  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
9097      match.pathname.substring(1) : match.pathname);
9098  locationObj.$$search = parseKeyValue(match.search);
9099  locationObj.$$hash = decodeURIComponent(match.hash);
9100
9101  // make sure path starts with '/';
9102  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
9103    locationObj.$$path = '/' + locationObj.$$path;
9104  }
9105}
9106
9107
9108/**
9109 *
9110 * @param {string} begin
9111 * @param {string} whole
9112 * @returns {string} returns text from whole after begin or undefined if it does not begin with
9113 *                   expected string.
9114 */
9115function beginsWith(begin, whole) {
9116  if (whole.indexOf(begin) === 0) {
9117    return whole.substr(begin.length);
9118  }
9119}
9120
9121
9122function stripHash(url) {
9123  var index = url.indexOf('#');
9124  return index == -1 ? url : url.substr(0, index);
9125}
9126
9127
9128function stripFile(url) {
9129  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9130}
9131
9132/* return the server only (scheme://host:port) */
9133function serverBase(url) {
9134  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9135}
9136
9137
9138/**
9139 * LocationHtml5Url represents an url
9140 * This object is exposed as $location service when HTML5 mode is enabled and supported
9141 *
9142 * @constructor
9143 * @param {string} appBase application base URL
9144 * @param {string} basePrefix url path prefix
9145 */
9146function LocationHtml5Url(appBase, basePrefix) {
9147  this.$$html5 = true;
9148  basePrefix = basePrefix || '';
9149  var appBaseNoFile = stripFile(appBase);
9150  parseAbsoluteUrl(appBase, this, appBase);
9151
9152
9153  /**
9154   * Parse given html5 (regular) url string into properties
9155   * @param {string} newAbsoluteUrl HTML5 url
9156   * @private
9157   */
9158  this.$$parse = function(url) {
9159    var pathUrl = beginsWith(appBaseNoFile, url);
9160    if (!isString(pathUrl)) {
9161      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9162          appBaseNoFile);
9163    }
9164
9165    parseAppUrl(pathUrl, this, appBase);
9166
9167    if (!this.$$path) {
9168      this.$$path = '/';
9169    }
9170
9171    this.$$compose();
9172  };
9173
9174  /**
9175   * Compose url and update `absUrl` property
9176   * @private
9177   */
9178  this.$$compose = function() {
9179    var search = toKeyValue(this.$$search),
9180        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9181
9182    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9183    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9184  };
9185
9186  this.$$rewrite = function(url) {
9187    var appUrl, prevAppUrl;
9188
9189    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
9190      prevAppUrl = appUrl;
9191      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
9192        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9193      } else {
9194        return appBase + prevAppUrl;
9195      }
9196    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
9197      return appBaseNoFile + appUrl;
9198    } else if (appBaseNoFile == url + '/') {
9199      return appBaseNoFile;
9200    }
9201  };
9202}
9203
9204
9205/**
9206 * LocationHashbangUrl represents url
9207 * This object is exposed as $location service when developer doesn't opt into html5 mode.
9208 * It also serves as the base class for html5 mode fallback on legacy browsers.
9209 *
9210 * @constructor
9211 * @param {string} appBase application base URL
9212 * @param {string} hashPrefix hashbang prefix
9213 */
9214function LocationHashbangUrl(appBase, hashPrefix) {
9215  var appBaseNoFile = stripFile(appBase);
9216
9217  parseAbsoluteUrl(appBase, this, appBase);
9218
9219
9220  /**
9221   * Parse given hashbang url into properties
9222   * @param {string} url Hashbang url
9223   * @private
9224   */
9225  this.$$parse = function(url) {
9226    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9227    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9228        ? beginsWith(hashPrefix, withoutBaseUrl)
9229        : (this.$$html5)
9230          ? withoutBaseUrl
9231          : '';
9232
9233    if (!isString(withoutHashUrl)) {
9234      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9235          hashPrefix);
9236    }
9237    parseAppUrl(withoutHashUrl, this, appBase);
9238
9239    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9240
9241    this.$$compose();
9242
9243    /*
9244     * In Windows, on an anchor node on documents loaded from
9245     * the filesystem, the browser will return a pathname
9246     * prefixed with the drive name ('/C:/path') when a
9247     * pathname without a drive is set:
9248     *  * a.setAttribute('href', '/foo')
9249     *   * a.pathname === '/C:/foo' //true
9250     *
9251     * Inside of Angular, we're always using pathnames that
9252     * do not include drive names for routing.
9253     */
9254    function removeWindowsDriveName (path, url, base) {
9255      /*
9256      Matches paths for file protocol on windows,
9257      such as /C:/foo/bar, and captures only /foo/bar.
9258      */
9259      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
9260
9261      var firstPathSegmentMatch;
9262
9263      //Get the relative path from the input URL.
9264      if (url.indexOf(base) === 0) {
9265        url = url.replace(base, '');
9266      }
9267
9268      // The input URL intentionally contains a first path segment that ends with a colon.
9269      if (windowsFilePathExp.exec(url)) {
9270        return path;
9271      }
9272
9273      firstPathSegmentMatch = windowsFilePathExp.exec(path);
9274      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9275    }
9276  };
9277
9278  /**
9279   * Compose hashbang url and update `absUrl` property
9280   * @private
9281   */
9282  this.$$compose = function() {
9283    var search = toKeyValue(this.$$search),
9284        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9285
9286    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9287    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9288  };
9289
9290  this.$$rewrite = function(url) {
9291    if(stripHash(appBase) == stripHash(url)) {
9292      return url;
9293    }
9294  };
9295}
9296
9297
9298/**
9299 * LocationHashbangUrl represents url
9300 * This object is exposed as $location service when html5 history api is enabled but the browser
9301 * does not support it.
9302 *
9303 * @constructor
9304 * @param {string} appBase application base URL
9305 * @param {string} hashPrefix hashbang prefix
9306 */
9307function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9308  this.$$html5 = true;
9309  LocationHashbangUrl.apply(this, arguments);
9310
9311  var appBaseNoFile = stripFile(appBase);
9312
9313  this.$$rewrite = function(url) {
9314    var appUrl;
9315
9316    if ( appBase == stripHash(url) ) {
9317      return url;
9318    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
9319      return appBase + hashPrefix + appUrl;
9320    } else if ( appBaseNoFile === url + '/') {
9321      return appBaseNoFile;
9322    }
9323  };
9324
9325  this.$$compose = function() {
9326    var search = toKeyValue(this.$$search),
9327        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9328
9329    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9330    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
9331    this.$$absUrl = appBase + hashPrefix + this.$$url;
9332  };
9333
9334}
9335
9336
9337LocationHashbangInHtml5Url.prototype =
9338  LocationHashbangUrl.prototype =
9339  LocationHtml5Url.prototype = {
9340
9341  /**
9342   * Are we in html5 mode?
9343   * @private
9344   */
9345  $$html5: false,
9346
9347  /**
9348   * Has any change been replacing ?
9349   * @private
9350   */
9351  $$replace: false,
9352
9353  /**
9354   * @ngdoc method
9355   * @name $location#absUrl
9356   *
9357   * @description
9358   * This method is getter only.
9359   *
9360   * Return full url representation with all segments encoded according to rules specified in
9361   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9362   *
9363   * @return {string} full url
9364   */
9365  absUrl: locationGetter('$$absUrl'),
9366
9367  /**
9368   * @ngdoc method
9369   * @name $location#url
9370   *
9371   * @description
9372   * This method is getter / setter.
9373   *
9374   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9375   *
9376   * Change path, search and hash, when called with parameter and return `$location`.
9377   *
9378   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9379   * @param {string=} replace The path that will be changed
9380   * @return {string} url
9381   */
9382  url: function(url, replace) {
9383    if (isUndefined(url))
9384      return this.$$url;
9385
9386    var match = PATH_MATCH.exec(url);
9387    if (match[1]) this.path(decodeURIComponent(match[1]));
9388    if (match[2] || match[1]) this.search(match[3] || '');
9389    this.hash(match[5] || '', replace);
9390
9391    return this;
9392  },
9393
9394  /**
9395   * @ngdoc method
9396   * @name $location#protocol
9397   *
9398   * @description
9399   * This method is getter only.
9400   *
9401   * Return protocol of current url.
9402   *
9403   * @return {string} protocol of current url
9404   */
9405  protocol: locationGetter('$$protocol'),
9406
9407  /**
9408   * @ngdoc method
9409   * @name $location#host
9410   *
9411   * @description
9412   * This method is getter only.
9413   *
9414   * Return host of current url.
9415   *
9416   * @return {string} host of current url.
9417   */
9418  host: locationGetter('$$host'),
9419
9420  /**
9421   * @ngdoc method
9422   * @name $location#port
9423   *
9424   * @description
9425   * This method is getter only.
9426   *
9427   * Return port of current url.
9428   *
9429   * @return {Number} port
9430   */
9431  port: locationGetter('$$port'),
9432
9433  /**
9434   * @ngdoc method
9435   * @name $location#path
9436   *
9437   * @description
9438   * This method is getter / setter.
9439   *
9440   * Return path of current url when called without any parameter.
9441   *
9442   * Change path when called with parameter and return `$location`.
9443   *
9444   * Note: Path should always begin with forward slash (/), this method will add the forward slash
9445   * if it is missing.
9446   *
9447   * @param {string=} path New path
9448   * @return {string} path
9449   */
9450  path: locationGetterSetter('$$path', function(path) {
9451    return path.charAt(0) == '/' ? path : '/' + path;
9452  }),
9453
9454  /**
9455   * @ngdoc method
9456   * @name $location#search
9457   *
9458   * @description
9459   * This method is getter / setter.
9460   *
9461   * Return search part (as object) of current url when called without any parameter.
9462   *
9463   * Change search part when called with parameter and return `$location`.
9464   *
9465   *
9466   * ```js
9467   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
9468   * var searchObject = $location.search();
9469   * // => {foo: 'bar', baz: 'xoxo'}
9470   *
9471   *
9472   * // set foo to 'yipee'
9473   * $location.search('foo', 'yipee');
9474   * // => $location
9475   * ```
9476   *
9477   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9478   * hash object.
9479   *
9480   * When called with a single argument the method acts as a setter, setting the `search` component
9481   * of `$location` to the specified value.
9482   *
9483   * If the argument is a hash object containing an array of values, these values will be encoded
9484   * as duplicate search parameters in the url.
9485   *
9486   * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will
9487   * override only a single search property.
9488   *
9489   * If `paramValue` is an array, it will override the property of the `search` component of
9490   * `$location` specified via the first argument.
9491   *
9492   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
9493   *
9494   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
9495   * one or more arguments returns `$location` object itself.
9496   */
9497  search: function(search, paramValue) {
9498    switch (arguments.length) {
9499      case 0:
9500        return this.$$search;
9501      case 1:
9502        if (isString(search)) {
9503          this.$$search = parseKeyValue(search);
9504        } else if (isObject(search)) {
9505          this.$$search = search;
9506        } else {
9507          throw $locationMinErr('isrcharg',
9508              'The first argument of the `$location#search()` call must be a string or an object.');
9509        }
9510        break;
9511      default:
9512        if (isUndefined(paramValue) || paramValue === null) {
9513          delete this.$$search[search];
9514        } else {
9515          this.$$search[search] = paramValue;
9516        }
9517    }
9518
9519    this.$$compose();
9520    return this;
9521  },
9522
9523  /**
9524   * @ngdoc method
9525   * @name $location#hash
9526   *
9527   * @description
9528   * This method is getter / setter.
9529   *
9530   * Return hash fragment when called without any parameter.
9531   *
9532   * Change hash fragment when called with parameter and return `$location`.
9533   *
9534   * @param {string=} hash New hash fragment
9535   * @return {string} hash
9536   */
9537  hash: locationGetterSetter('$$hash', identity),
9538
9539  /**
9540   * @ngdoc method
9541   * @name $location#replace
9542   *
9543   * @description
9544   * If called, all changes to $location during current `$digest` will be replacing current history
9545   * record, instead of adding new one.
9546   */
9547  replace: function() {
9548    this.$$replace = true;
9549    return this;
9550  }
9551};
9552
9553function locationGetter(property) {
9554  return function() {
9555    return this[property];
9556  };
9557}
9558
9559
9560function locationGetterSetter(property, preprocess) {
9561  return function(value) {
9562    if (isUndefined(value))
9563      return this[property];
9564
9565    this[property] = preprocess(value);
9566    this.$$compose();
9567
9568    return this;
9569  };
9570}
9571
9572
9573/**
9574 * @ngdoc service
9575 * @name $location
9576 *
9577 * @requires $rootElement
9578 *
9579 * @description
9580 * The $location service parses the URL in the browser address bar (based on the
9581 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9582 * available to your application. Changes to the URL in the address bar are reflected into
9583 * $location service and changes to $location are reflected into the browser address bar.
9584 *
9585 * **The $location service:**
9586 *
9587 * - Exposes the current URL in the browser address bar, so you can
9588 *   - Watch and observe the URL.
9589 *   - Change the URL.
9590 * - Synchronizes the URL with the browser when the user
9591 *   - Changes the address bar.
9592 *   - Clicks the back or forward button (or clicks a History link).
9593 *   - Clicks on a link.
9594 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9595 *
9596 * For more information see {@link guide/$location Developer Guide: Using $location}
9597 */
9598
9599/**
9600 * @ngdoc provider
9601 * @name $locationProvider
9602 * @description
9603 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9604 */
9605function $LocationProvider(){
9606  var hashPrefix = '',
9607      html5Mode = false;
9608
9609  /**
9610   * @ngdoc method
9611   * @name $locationProvider#hashPrefix
9612   * @description
9613   * @param {string=} prefix Prefix for hash part (containing path and search)
9614   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9615   */
9616  this.hashPrefix = function(prefix) {
9617    if (isDefined(prefix)) {
9618      hashPrefix = prefix;
9619      return this;
9620    } else {
9621      return hashPrefix;
9622    }
9623  };
9624
9625  /**
9626   * @ngdoc method
9627   * @name $locationProvider#html5Mode
9628   * @description
9629   * @param {boolean=} mode Use HTML5 strategy if available.
9630   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9631   */
9632  this.html5Mode = function(mode) {
9633    if (isDefined(mode)) {
9634      html5Mode = mode;
9635      return this;
9636    } else {
9637      return html5Mode;
9638    }
9639  };
9640
9641  /**
9642   * @ngdoc event
9643   * @name $location#$locationChangeStart
9644   * @eventType broadcast on root scope
9645   * @description
9646   * Broadcasted before a URL will change. This change can be prevented by calling
9647   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9648   * details about event object. Upon successful change
9649   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9650   *
9651   * @param {Object} angularEvent Synthetic event object.
9652   * @param {string} newUrl New URL
9653   * @param {string=} oldUrl URL that was before it was changed.
9654   */
9655
9656  /**
9657   * @ngdoc event
9658   * @name $location#$locationChangeSuccess
9659   * @eventType broadcast on root scope
9660   * @description
9661   * Broadcasted after a URL was changed.
9662   *
9663   * @param {Object} angularEvent Synthetic event object.
9664   * @param {string} newUrl New URL
9665   * @param {string=} oldUrl URL that was before it was changed.
9666   */
9667
9668  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9669      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9670    var $location,
9671        LocationMode,
9672        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9673        initialUrl = $browser.url(),
9674        appBase;
9675
9676    if (html5Mode) {
9677      appBase = serverBase(initialUrl) + (baseHref || '/');
9678      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9679    } else {
9680      appBase = stripHash(initialUrl);
9681      LocationMode = LocationHashbangUrl;
9682    }
9683    $location = new LocationMode(appBase, '#' + hashPrefix);
9684    $location.$$parse($location.$$rewrite(initialUrl));
9685
9686    $rootElement.on('click', function(event) {
9687      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9688      // currently we open nice url link and redirect then
9689
9690      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9691
9692      var elm = jqLite(event.target);
9693
9694      // traverse the DOM up to find first A tag
9695      while (lowercase(elm[0].nodeName) !== 'a') {
9696        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9697        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9698      }
9699
9700      var absHref = elm.prop('href');
9701
9702      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9703        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9704        // an animation.
9705        absHref = urlResolve(absHref.animVal).href;
9706      }
9707
9708      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
9709      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
9710      // somewhere#anchor or http://example.com/somewhere
9711      if (LocationMode === LocationHashbangInHtml5Url) {
9712        // get the actual href attribute - see
9713        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9714        var href = elm.attr('href') || elm.attr('xlink:href');
9715
9716        if (href.indexOf('://') < 0) {         // Ignore absolute URLs
9717          var prefix = '#' + hashPrefix;
9718          if (href[0] == '/') {
9719            // absolute path - replace old path
9720            absHref = appBase + prefix + href;
9721          } else if (href[0] == '#') {
9722            // local anchor
9723            absHref = appBase + prefix + ($location.path() || '/') + href;
9724          } else {
9725            // relative path - join with current path
9726            var stack = $location.path().split("/"),
9727              parts = href.split("/");
9728            for (var i=0; i<parts.length; i++) {
9729              if (parts[i] == ".")
9730                continue;
9731              else if (parts[i] == "..")
9732                stack.pop();
9733              else if (parts[i].length)
9734                stack.push(parts[i]);
9735            }
9736            absHref = appBase + prefix + stack.join('/');
9737          }
9738        }
9739      }
9740
9741      var rewrittenUrl = $location.$$rewrite(absHref);
9742
9743      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9744        event.preventDefault();
9745        if (rewrittenUrl != $browser.url()) {
9746          // update location manually
9747          $location.$$parse(rewrittenUrl);
9748          $rootScope.$apply();
9749          // hack to work around FF6 bug 684208 when scenario runner clicks on links
9750          window.angular['ff-684208-preventDefault'] = true;
9751        }
9752      }
9753    });
9754
9755
9756    // rewrite hashbang url <> html5 url
9757    if ($location.absUrl() != initialUrl) {
9758      $browser.url($location.absUrl(), true);
9759    }
9760
9761    // update $location when $browser url changes
9762    $browser.onUrlChange(function(newUrl) {
9763      if ($location.absUrl() != newUrl) {
9764        $rootScope.$evalAsync(function() {
9765          var oldUrl = $location.absUrl();
9766
9767          $location.$$parse(newUrl);
9768          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9769                                    oldUrl).defaultPrevented) {
9770            $location.$$parse(oldUrl);
9771            $browser.url(oldUrl);
9772          } else {
9773            afterLocationChange(oldUrl);
9774          }
9775        });
9776        if (!$rootScope.$$phase) $rootScope.$digest();
9777      }
9778    });
9779
9780    // update browser
9781    var changeCounter = 0;
9782    $rootScope.$watch(function $locationWatch() {
9783      var oldUrl = $browser.url();
9784      var currentReplace = $location.$$replace;
9785
9786      if (!changeCounter || oldUrl != $location.absUrl()) {
9787        changeCounter++;
9788        $rootScope.$evalAsync(function() {
9789          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9790              defaultPrevented) {
9791            $location.$$parse(oldUrl);
9792          } else {
9793            $browser.url($location.absUrl(), currentReplace);
9794            afterLocationChange(oldUrl);
9795          }
9796        });
9797      }
9798      $location.$$replace = false;
9799
9800      return changeCounter;
9801    });
9802
9803    return $location;
9804
9805    function afterLocationChange(oldUrl) {
9806      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9807    }
9808}];
9809}
9810
9811/**
9812 * @ngdoc service
9813 * @name $log
9814 * @requires $window
9815 *
9816 * @description
9817 * Simple service for logging. Default implementation safely writes the message
9818 * into the browser's console (if present).
9819 *
9820 * The main purpose of this service is to simplify debugging and troubleshooting.
9821 *
9822 * The default is to log `debug` messages. You can use
9823 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9824 *
9825 * @example
9826   <example>
9827     <file name="script.js">
9828       function LogCtrl($scope, $log) {
9829         $scope.$log = $log;
9830         $scope.message = 'Hello World!';
9831       }
9832     </file>
9833     <file name="index.html">
9834       <div ng-controller="LogCtrl">
9835         <p>Reload this page with open console, enter text and hit the log button...</p>
9836         Message:
9837         <input type="text" ng-model="message"/>
9838         <button ng-click="$log.log(message)">log</button>
9839         <button ng-click="$log.warn(message)">warn</button>
9840         <button ng-click="$log.info(message)">info</button>
9841         <button ng-click="$log.error(message)">error</button>
9842       </div>
9843     </file>
9844   </example>
9845 */
9846
9847/**
9848 * @ngdoc provider
9849 * @name $logProvider
9850 * @description
9851 * Use the `$logProvider` to configure how the application logs messages
9852 */
9853function $LogProvider(){
9854  var debug = true,
9855      self = this;
9856
9857  /**
9858   * @ngdoc property
9859   * @name $logProvider#debugEnabled
9860   * @description
9861   * @param {boolean=} flag enable or disable debug level messages
9862   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9863   */
9864  this.debugEnabled = function(flag) {
9865    if (isDefined(flag)) {
9866      debug = flag;
9867    return this;
9868    } else {
9869      return debug;
9870    }
9871  };
9872
9873  this.$get = ['$window', function($window){
9874    return {
9875      /**
9876       * @ngdoc method
9877       * @name $log#log
9878       *
9879       * @description
9880       * Write a log message
9881       */
9882      log: consoleLog('log'),
9883
9884      /**
9885       * @ngdoc method
9886       * @name $log#info
9887       *
9888       * @description
9889       * Write an information message
9890       */
9891      info: consoleLog('info'),
9892
9893      /**
9894       * @ngdoc method
9895       * @name $log#warn
9896       *
9897       * @description
9898       * Write a warning message
9899       */
9900      warn: consoleLog('warn'),
9901
9902      /**
9903       * @ngdoc method
9904       * @name $log#error
9905       *
9906       * @description
9907       * Write an error message
9908       */
9909      error: consoleLog('error'),
9910
9911      /**
9912       * @ngdoc method
9913       * @name $log#debug
9914       *
9915       * @description
9916       * Write a debug message
9917       */
9918      debug: (function () {
9919        var fn = consoleLog('debug');
9920
9921        return function() {
9922          if (debug) {
9923            fn.apply(self, arguments);
9924          }
9925        };
9926      }())
9927    };
9928
9929    function formatError(arg) {
9930      if (arg instanceof Error) {
9931        if (arg.stack) {
9932          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
9933              ? 'Error: ' + arg.message + '\n' + arg.stack
9934              : arg.stack;
9935        } else if (arg.sourceURL) {
9936          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
9937        }
9938      }
9939      return arg;
9940    }
9941
9942    function consoleLog(type) {
9943      var console = $window.console || {},
9944          logFn = console[type] || console.log || noop,
9945          hasApply = false;
9946
9947      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
9948      // The reason behind this is that console.log has type "object" in IE8...
9949      try {
9950        hasApply = !!logFn.apply;
9951      } catch (e) {}
9952
9953      if (hasApply) {
9954        return function() {
9955          var args = [];
9956          forEach(arguments, function(arg) {
9957            args.push(formatError(arg));
9958          });
9959          return logFn.apply(console, args);
9960        };
9961      }
9962
9963      // we are IE which either doesn't have window.console => this is noop and we do nothing,
9964      // or we are IE where console.log doesn't have apply so we log at least first 2 args
9965      return function(arg1, arg2) {
9966        logFn(arg1, arg2 == null ? '' : arg2);
9967      };
9968    }
9969  }];
9970}
9971
9972var $parseMinErr = minErr('$parse');
9973var promiseWarningCache = {};
9974var promiseWarning;
9975
9976// Sandboxing Angular Expressions
9977// ------------------------------
9978// Angular expressions are generally considered safe because these expressions only have direct
9979// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9980// obtaining a reference to native JS functions such as the Function constructor.
9981//
9982// As an example, consider the following Angular expression:
9983//
9984//   {}.toString.constructor('alert("evil JS code")')
9985//
9986// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9987// against the expression language, but not to prevent exploits that were enabled by exposing
9988// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
9989// practice and therefore we are not even trying to protect against interaction with an object
9990// explicitly exposed in this way.
9991//
9992// In general, it is not possible to access a Window object from an angular expression unless a
9993// window or some DOM object that has a reference to window is published onto a Scope.
9994// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
9995// native objects.
9996
9997
9998function ensureSafeMemberName(name, fullExpression) {
9999  if (name === "__defineGetter__" || name === "__defineSetter__"
10000      || name === "__lookupGetter__" || name === "__lookupSetter__"
10001      || name === "__proto__") {
10002    throw $parseMinErr('isecfld',
10003        'Attempting to access a disallowed field in Angular expressions! '
10004        +'Expression: {0}', fullExpression);
10005  }
10006  return name;
10007}
10008
10009function ensureSafeObject(obj, fullExpression) {
10010  // nifty check if obj is Function that is fast and works across iframes and other contexts
10011  if (obj) {
10012    if (obj.constructor === obj) {
10013      throw $parseMinErr('isecfn',
10014          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10015          fullExpression);
10016    } else if (// isWindow(obj)
10017        obj.document && obj.location && obj.alert && obj.setInterval) {
10018      throw $parseMinErr('isecwindow',
10019          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
10020          fullExpression);
10021    } else if (// isElement(obj)
10022        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
10023      throw $parseMinErr('isecdom',
10024          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
10025          fullExpression);
10026    } else if (// block Object so that we can't get hold of dangerous Object.* methods
10027        obj === Object) {
10028      throw $parseMinErr('isecobj',
10029          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
10030          fullExpression);
10031    }
10032  }
10033  return obj;
10034}
10035
10036var CALL = Function.prototype.call;
10037var APPLY = Function.prototype.apply;
10038var BIND = Function.prototype.bind;
10039
10040function ensureSafeFunction(obj, fullExpression) {
10041  if (obj) {
10042    if (obj.constructor === obj) {
10043      throw $parseMinErr('isecfn',
10044        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10045        fullExpression);
10046    } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
10047      throw $parseMinErr('isecff',
10048        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
10049        fullExpression);
10050    }
10051  }
10052}
10053
10054var OPERATORS = {
10055    /* jshint bitwise : false */
10056    'null':function(){return null;},
10057    'true':function(){return true;},
10058    'false':function(){return false;},
10059    undefined:noop,
10060    '+':function(self, locals, a,b){
10061      a=a(self, locals); b=b(self, locals);
10062      if (isDefined(a)) {
10063        if (isDefined(b)) {
10064          return a + b;
10065        }
10066        return a;
10067      }
10068      return isDefined(b)?b:undefined;},
10069    '-':function(self, locals, a,b){
10070          a=a(self, locals); b=b(self, locals);
10071          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
10072        },
10073    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
10074    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
10075    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
10076    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
10077    '=':noop,
10078    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
10079    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
10080    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
10081    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
10082    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
10083    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
10084    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
10085    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
10086    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
10087    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
10088    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
10089//    '|':function(self, locals, a,b){return a|b;},
10090    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
10091    '!':function(self, locals, a){return !a(self, locals);}
10092};
10093/* jshint bitwise: true */
10094var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
10095
10096
10097/////////////////////////////////////////
10098
10099
10100/**
10101 * @constructor
10102 */
10103var Lexer = function (options) {
10104  this.options = options;
10105};
10106
10107Lexer.prototype = {
10108  constructor: Lexer,
10109
10110  lex: function (text) {
10111    this.text = text;
10112
10113    this.index = 0;
10114    this.ch = undefined;
10115    this.lastCh = ':'; // can start regexp
10116
10117    this.tokens = [];
10118
10119    while (this.index < this.text.length) {
10120      this.ch = this.text.charAt(this.index);
10121      if (this.is('"\'')) {
10122        this.readString(this.ch);
10123      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
10124        this.readNumber();
10125      } else if (this.isIdent(this.ch)) {
10126        this.readIdent();
10127      } else if (this.is('(){}[].,;:?')) {
10128        this.tokens.push({
10129          index: this.index,
10130          text: this.ch
10131        });
10132        this.index++;
10133      } else if (this.isWhitespace(this.ch)) {
10134        this.index++;
10135        continue;
10136      } else {
10137        var ch2 = this.ch + this.peek();
10138        var ch3 = ch2 + this.peek(2);
10139        var fn = OPERATORS[this.ch];
10140        var fn2 = OPERATORS[ch2];
10141        var fn3 = OPERATORS[ch3];
10142        if (fn3) {
10143          this.tokens.push({index: this.index, text: ch3, fn: fn3});
10144          this.index += 3;
10145        } else if (fn2) {
10146          this.tokens.push({index: this.index, text: ch2, fn: fn2});
10147          this.index += 2;
10148        } else if (fn) {
10149          this.tokens.push({
10150            index: this.index,
10151            text: this.ch,
10152            fn: fn
10153          });
10154          this.index += 1;
10155        } else {
10156          this.throwError('Unexpected next character ', this.index, this.index + 1);
10157        }
10158      }
10159      this.lastCh = this.ch;
10160    }
10161    return this.tokens;
10162  },
10163
10164  is: function(chars) {
10165    return chars.indexOf(this.ch) !== -1;
10166  },
10167
10168  was: function(chars) {
10169    return chars.indexOf(this.lastCh) !== -1;
10170  },
10171
10172  peek: function(i) {
10173    var num = i || 1;
10174    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
10175  },
10176
10177  isNumber: function(ch) {
10178    return ('0' <= ch && ch <= '9');
10179  },
10180
10181  isWhitespace: function(ch) {
10182    // IE treats non-breaking space as \u00A0
10183    return (ch === ' ' || ch === '\r' || ch === '\t' ||
10184            ch === '\n' || ch === '\v' || ch === '\u00A0');
10185  },
10186
10187  isIdent: function(ch) {
10188    return ('a' <= ch && ch <= 'z' ||
10189            'A' <= ch && ch <= 'Z' ||
10190            '_' === ch || ch === '$');
10191  },
10192
10193  isExpOperator: function(ch) {
10194    return (ch === '-' || ch === '+' || this.isNumber(ch));
10195  },
10196
10197  throwError: function(error, start, end) {
10198    end = end || this.index;
10199    var colStr = (isDefined(start)
10200            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10201            : ' ' + end);
10202    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10203        error, colStr, this.text);
10204  },
10205
10206  readNumber: function() {
10207    var number = '';
10208    var start = this.index;
10209    while (this.index < this.text.length) {
10210      var ch = lowercase(this.text.charAt(this.index));
10211      if (ch == '.' || this.isNumber(ch)) {
10212        number += ch;
10213      } else {
10214        var peekCh = this.peek();
10215        if (ch == 'e' && this.isExpOperator(peekCh)) {
10216          number += ch;
10217        } else if (this.isExpOperator(ch) &&
10218            peekCh && this.isNumber(peekCh) &&
10219            number.charAt(number.length - 1) == 'e') {
10220          number += ch;
10221        } else if (this.isExpOperator(ch) &&
10222            (!peekCh || !this.isNumber(peekCh)) &&
10223            number.charAt(number.length - 1) == 'e') {
10224          this.throwError('Invalid exponent');
10225        } else {
10226          break;
10227        }
10228      }
10229      this.index++;
10230    }
10231    number = 1 * number;
10232    this.tokens.push({
10233      index: start,
10234      text: number,
10235      literal: true,
10236      constant: true,
10237      fn: function() { return number; }
10238    });
10239  },
10240
10241  readIdent: function() {
10242    var parser = this;
10243
10244    var ident = '';
10245    var start = this.index;
10246
10247    var lastDot, peekIndex, methodName, ch;
10248
10249    while (this.index < this.text.length) {
10250      ch = this.text.charAt(this.index);
10251      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10252        if (ch === '.') lastDot = this.index;
10253        ident += ch;
10254      } else {
10255        break;
10256      }
10257      this.index++;
10258    }
10259
10260    //check if this is not a method invocation and if it is back out to last dot
10261    if (lastDot) {
10262      peekIndex = this.index;
10263      while (peekIndex < this.text.length) {
10264        ch = this.text.charAt(peekIndex);
10265        if (ch === '(') {
10266          methodName = ident.substr(lastDot - start + 1);
10267          ident = ident.substr(0, lastDot - start);
10268          this.index = peekIndex;
10269          break;
10270        }
10271        if (this.isWhitespace(ch)) {
10272          peekIndex++;
10273        } else {
10274          break;
10275        }
10276      }
10277    }
10278
10279
10280    var token = {
10281      index: start,
10282      text: ident
10283    };
10284
10285    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10286    if (OPERATORS.hasOwnProperty(ident)) {
10287      token.fn = OPERATORS[ident];
10288      token.literal = true;
10289      token.constant = true;
10290    } else {
10291      var getter = getterFn(ident, this.options, this.text);
10292      token.fn = extend(function(self, locals) {
10293        return (getter(self, locals));
10294      }, {
10295        assign: function(self, value) {
10296          return setter(self, ident, value, parser.text, parser.options);
10297        }
10298      });
10299    }
10300
10301    this.tokens.push(token);
10302
10303    if (methodName) {
10304      this.tokens.push({
10305        index:lastDot,
10306        text: '.'
10307      });
10308      this.tokens.push({
10309        index: lastDot + 1,
10310        text: methodName
10311      });
10312    }
10313  },
10314
10315  readString: function(quote) {
10316    var start = this.index;
10317    this.index++;
10318    var string = '';
10319    var rawString = quote;
10320    var escape = false;
10321    while (this.index < this.text.length) {
10322      var ch = this.text.charAt(this.index);
10323      rawString += ch;
10324      if (escape) {
10325        if (ch === 'u') {
10326          var hex = this.text.substring(this.index + 1, this.index + 5);
10327          if (!hex.match(/[\da-f]{4}/i))
10328            this.throwError('Invalid unicode escape [\\u' + hex + ']');
10329          this.index += 4;
10330          string += String.fromCharCode(parseInt(hex, 16));
10331        } else {
10332          var rep = ESCAPE[ch];
10333          if (rep) {
10334            string += rep;
10335          } else {
10336            string += ch;
10337          }
10338        }
10339        escape = false;
10340      } else if (ch === '\\') {
10341        escape = true;
10342      } else if (ch === quote) {
10343        this.index++;
10344        this.tokens.push({
10345          index: start,
10346          text: rawString,
10347          string: string,
10348          literal: true,
10349          constant: true,
10350          fn: function() { return string; }
10351        });
10352        return;
10353      } else {
10354        string += ch;
10355      }
10356      this.index++;
10357    }
10358    this.throwError('Unterminated quote', start);
10359  }
10360};
10361
10362
10363/**
10364 * @constructor
10365 */
10366var Parser = function (lexer, $filter, options) {
10367  this.lexer = lexer;
10368  this.$filter = $filter;
10369  this.options = options;
10370};
10371
10372Parser.ZERO = extend(function () {
10373  return 0;
10374}, {
10375  constant: true
10376});
10377
10378Parser.prototype = {
10379  constructor: Parser,
10380
10381  parse: function (text) {
10382    this.text = text;
10383
10384    this.tokens = this.lexer.lex(text);
10385
10386    var value = this.statements();
10387
10388    if (this.tokens.length !== 0) {
10389      this.throwError('is an unexpected token', this.tokens[0]);
10390    }
10391
10392    value.literal = !!value.literal;
10393    value.constant = !!value.constant;
10394
10395    return value;
10396  },
10397
10398  primary: function () {
10399    var primary;
10400    if (this.expect('(')) {
10401      primary = this.filterChain();
10402      this.consume(')');
10403    } else if (this.expect('[')) {
10404      primary = this.arrayDeclaration();
10405    } else if (this.expect('{')) {
10406      primary = this.object();
10407    } else {
10408      var token = this.expect();
10409      primary = token.fn;
10410      if (!primary) {
10411        this.throwError('not a primary expression', token);
10412      }
10413      primary.literal = !!token.literal;
10414      primary.constant = !!token.constant;
10415    }
10416
10417    var next, context;
10418    while ((next = this.expect('(', '[', '.'))) {
10419      if (next.text === '(') {
10420        primary = this.functionCall(primary, context);
10421        context = null;
10422      } else if (next.text === '[') {
10423        context = primary;
10424        primary = this.objectIndex(primary);
10425      } else if (next.text === '.') {
10426        context = primary;
10427        primary = this.fieldAccess(primary);
10428      } else {
10429        this.throwError('IMPOSSIBLE');
10430      }
10431    }
10432    return primary;
10433  },
10434
10435  throwError: function(msg, token) {
10436    throw $parseMinErr('syntax',
10437        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10438          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10439  },
10440
10441  peekToken: function() {
10442    if (this.tokens.length === 0)
10443      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10444    return this.tokens[0];
10445  },
10446
10447  peek: function(e1, e2, e3, e4) {
10448    if (this.tokens.length > 0) {
10449      var token = this.tokens[0];
10450      var t = token.text;
10451      if (t === e1 || t === e2 || t === e3 || t === e4 ||
10452          (!e1 && !e2 && !e3 && !e4)) {
10453        return token;
10454      }
10455    }
10456    return false;
10457  },
10458
10459  expect: function(e1, e2, e3, e4){
10460    var token = this.peek(e1, e2, e3, e4);
10461    if (token) {
10462      this.tokens.shift();
10463      return token;
10464    }
10465    return false;
10466  },
10467
10468  consume: function(e1){
10469    if (!this.expect(e1)) {
10470      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10471    }
10472  },
10473
10474  unaryFn: function(fn, right) {
10475    return extend(function(self, locals) {
10476      return fn(self, locals, right);
10477    }, {
10478      constant:right.constant
10479    });
10480  },
10481
10482  ternaryFn: function(left, middle, right){
10483    return extend(function(self, locals){
10484      return left(self, locals) ? middle(self, locals) : right(self, locals);
10485    }, {
10486      constant: left.constant && middle.constant && right.constant
10487    });
10488  },
10489
10490  binaryFn: function(left, fn, right) {
10491    return extend(function(self, locals) {
10492      return fn(self, locals, left, right);
10493    }, {
10494      constant:left.constant && right.constant
10495    });
10496  },
10497
10498  statements: function() {
10499    var statements = [];
10500    while (true) {
10501      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10502        statements.push(this.filterChain());
10503      if (!this.expect(';')) {
10504        // optimize for the common case where there is only one statement.
10505        // TODO(size): maybe we should not support multiple statements?
10506        return (statements.length === 1)
10507            ? statements[0]
10508            : function(self, locals) {
10509                var value;
10510                for (var i = 0; i < statements.length; i++) {
10511                  var statement = statements[i];
10512                  if (statement) {
10513                    value = statement(self, locals);
10514                  }
10515                }
10516                return value;
10517              };
10518      }
10519    }
10520  },
10521
10522  filterChain: function() {
10523    var left = this.expression();
10524    var token;
10525    while (true) {
10526      if ((token = this.expect('|'))) {
10527        left = this.binaryFn(left, token.fn, this.filter());
10528      } else {
10529        return left;
10530      }
10531    }
10532  },
10533
10534  filter: function() {
10535    var token = this.expect();
10536    var fn = this.$filter(token.text);
10537    var argsFn = [];
10538    while (true) {
10539      if ((token = this.expect(':'))) {
10540        argsFn.push(this.expression());
10541      } else {
10542        var fnInvoke = function(self, locals, input) {
10543          var args = [input];
10544          for (var i = 0; i < argsFn.length; i++) {
10545            args.push(argsFn[i](self, locals));
10546          }
10547          return fn.apply(self, args);
10548        };
10549        return function() {
10550          return fnInvoke;
10551        };
10552      }
10553    }
10554  },
10555
10556  expression: function() {
10557    return this.assignment();
10558  },
10559
10560  assignment: function() {
10561    var left = this.ternary();
10562    var right;
10563    var token;
10564    if ((token = this.expect('='))) {
10565      if (!left.assign) {
10566        this.throwError('implies assignment but [' +
10567            this.text.substring(0, token.index) + '] can not be assigned to', token);
10568      }
10569      right = this.ternary();
10570      return function(scope, locals) {
10571        return left.assign(scope, right(scope, locals), locals);
10572      };
10573    }
10574    return left;
10575  },
10576
10577  ternary: function() {
10578    var left = this.logicalOR();
10579    var middle;
10580    var token;
10581    if ((token = this.expect('?'))) {
10582      middle = this.ternary();
10583      if ((token = this.expect(':'))) {
10584        return this.ternaryFn(left, middle, this.ternary());
10585      } else {
10586        this.throwError('expected :', token);
10587      }
10588    } else {
10589      return left;
10590    }
10591  },
10592
10593  logicalOR: function() {
10594    var left = this.logicalAND();
10595    var token;
10596    while (true) {
10597      if ((token = this.expect('||'))) {
10598        left = this.binaryFn(left, token.fn, this.logicalAND());
10599      } else {
10600        return left;
10601      }
10602    }
10603  },
10604
10605  logicalAND: function() {
10606    var left = this.equality();
10607    var token;
10608    if ((token = this.expect('&&'))) {
10609      left = this.binaryFn(left, token.fn, this.logicalAND());
10610    }
10611    return left;
10612  },
10613
10614  equality: function() {
10615    var left = this.relational();
10616    var token;
10617    if ((token = this.expect('==','!=','===','!=='))) {
10618      left = this.binaryFn(left, token.fn, this.equality());
10619    }
10620    return left;
10621  },
10622
10623  relational: function() {
10624    var left = this.additive();
10625    var token;
10626    if ((token = this.expect('<', '>', '<=', '>='))) {
10627      left = this.binaryFn(left, token.fn, this.relational());
10628    }
10629    return left;
10630  },
10631
10632  additive: function() {
10633    var left = this.multiplicative();
10634    var token;
10635    while ((token = this.expect('+','-'))) {
10636      left = this.binaryFn(left, token.fn, this.multiplicative());
10637    }
10638    return left;
10639  },
10640
10641  multiplicative: function() {
10642    var left = this.unary();
10643    var token;
10644    while ((token = this.expect('*','/','%'))) {
10645      left = this.binaryFn(left, token.fn, this.unary());
10646    }
10647    return left;
10648  },
10649
10650  unary: function() {
10651    var token;
10652    if (this.expect('+')) {
10653      return this.primary();
10654    } else if ((token = this.expect('-'))) {
10655      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10656    } else if ((token = this.expect('!'))) {
10657      return this.unaryFn(token.fn, this.unary());
10658    } else {
10659      return this.primary();
10660    }
10661  },
10662
10663  fieldAccess: function(object) {
10664    var parser = this;
10665    var field = this.expect().text;
10666    var getter = getterFn(field, this.options, this.text);
10667
10668    return extend(function(scope, locals, self) {
10669      return getter(self || object(scope, locals));
10670    }, {
10671      assign: function(scope, value, locals) {
10672        return setter(object(scope, locals), field, value, parser.text, parser.options);
10673      }
10674    });
10675  },
10676
10677  objectIndex: function(obj) {
10678    var parser = this;
10679
10680    var indexFn = this.expression();
10681    this.consume(']');
10682
10683    return extend(function(self, locals) {
10684      var o = obj(self, locals),
10685          i = indexFn(self, locals),
10686          v, p;
10687
10688      ensureSafeMemberName(i, parser.text);
10689      if (!o) return undefined;
10690      v = ensureSafeObject(o[i], parser.text);
10691      if (v && v.then && parser.options.unwrapPromises) {
10692        p = v;
10693        if (!('$$v' in v)) {
10694          p.$$v = undefined;
10695          p.then(function(val) { p.$$v = val; });
10696        }
10697        v = v.$$v;
10698      }
10699      return v;
10700    }, {
10701      assign: function(self, value, locals) {
10702        var key = indexFn(self, locals);
10703        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10704        var safe = ensureSafeObject(obj(self, locals), parser.text);
10705        return safe[key] = value;
10706      }
10707    });
10708  },
10709
10710  functionCall: function(fn, contextGetter) {
10711    var argsFn = [];
10712    if (this.peekToken().text !== ')') {
10713      do {
10714        argsFn.push(this.expression());
10715      } while (this.expect(','));
10716    }
10717    this.consume(')');
10718
10719    var parser = this;
10720
10721    return function(scope, locals) {
10722      var args = [];
10723      var context = contextGetter ? contextGetter(scope, locals) : scope;
10724
10725      for (var i = 0; i < argsFn.length; i++) {
10726        args.push(argsFn[i](scope, locals));
10727      }
10728      var fnPtr = fn(scope, locals, context) || noop;
10729
10730      ensureSafeObject(context, parser.text);
10731      ensureSafeFunction(fnPtr, parser.text);
10732
10733      // IE stupidity! (IE doesn't have apply for some native functions)
10734      var v = fnPtr.apply
10735            ? fnPtr.apply(context, args)
10736            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10737
10738      return ensureSafeObject(v, parser.text);
10739    };
10740  },
10741
10742  // This is used with json array declaration
10743  arrayDeclaration: function () {
10744    var elementFns = [];
10745    var allConstant = true;
10746    if (this.peekToken().text !== ']') {
10747      do {
10748        if (this.peek(']')) {
10749          // Support trailing commas per ES5.1.
10750          break;
10751        }
10752        var elementFn = this.expression();
10753        elementFns.push(elementFn);
10754        if (!elementFn.constant) {
10755          allConstant = false;
10756        }
10757      } while (this.expect(','));
10758    }
10759    this.consume(']');
10760
10761    return extend(function(self, locals) {
10762      var array = [];
10763      for (var i = 0; i < elementFns.length; i++) {
10764        array.push(elementFns[i](self, locals));
10765      }
10766      return array;
10767    }, {
10768      literal: true,
10769      constant: allConstant
10770    });
10771  },
10772
10773  object: function () {
10774    var keyValues = [];
10775    var allConstant = true;
10776    if (this.peekToken().text !== '}') {
10777      do {
10778        if (this.peek('}')) {
10779          // Support trailing commas per ES5.1.
10780          break;
10781        }
10782        var token = this.expect(),
10783        key = token.string || token.text;
10784        this.consume(':');
10785        var value = this.expression();
10786        keyValues.push({key: key, value: value});
10787        if (!value.constant) {
10788          allConstant = false;
10789        }
10790      } while (this.expect(','));
10791    }
10792    this.consume('}');
10793
10794    return extend(function(self, locals) {
10795      var object = {};
10796      for (var i = 0; i < keyValues.length; i++) {
10797        var keyValue = keyValues[i];
10798        object[keyValue.key] = keyValue.value(self, locals);
10799      }
10800      return object;
10801    }, {
10802      literal: true,
10803      constant: allConstant
10804    });
10805  }
10806};
10807
10808
10809//////////////////////////////////////////////////
10810// Parser helper functions
10811//////////////////////////////////////////////////
10812
10813function setter(obj, path, setValue, fullExp, options) {
10814  //needed?
10815  options = options || {};
10816
10817  var element = path.split('.'), key;
10818  for (var i = 0; element.length > 1; i++) {
10819    key = ensureSafeMemberName(element.shift(), fullExp);
10820    var propertyObj = obj[key];
10821    if (!propertyObj) {
10822      propertyObj = {};
10823      obj[key] = propertyObj;
10824    }
10825    obj = propertyObj;
10826    if (obj.then && options.unwrapPromises) {
10827      promiseWarning(fullExp);
10828      if (!("$$v" in obj)) {
10829        (function(promise) {
10830          promise.then(function(val) { promise.$$v = val; }); }
10831        )(obj);
10832      }
10833      if (obj.$$v === undefined) {
10834        obj.$$v = {};
10835      }
10836      obj = obj.$$v;
10837    }
10838  }
10839  key = ensureSafeMemberName(element.shift(), fullExp);
10840  ensureSafeObject(obj, fullExp);
10841  ensureSafeObject(obj[key], fullExp);
10842  obj[key] = setValue;
10843  return setValue;
10844}
10845
10846var getterFnCache = {};
10847
10848/**
10849 * Implementation of the "Black Hole" variant from:
10850 * - http://jsperf.com/angularjs-parse-getter/4
10851 * - http://jsperf.com/path-evaluation-simplified/7
10852 */
10853function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10854  ensureSafeMemberName(key0, fullExp);
10855  ensureSafeMemberName(key1, fullExp);
10856  ensureSafeMemberName(key2, fullExp);
10857  ensureSafeMemberName(key3, fullExp);
10858  ensureSafeMemberName(key4, fullExp);
10859
10860  return !options.unwrapPromises
10861      ? function cspSafeGetter(scope, locals) {
10862          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10863
10864          if (pathVal == null) return pathVal;
10865          pathVal = pathVal[key0];
10866
10867          if (!key1) return pathVal;
10868          if (pathVal == null) return undefined;
10869          pathVal = pathVal[key1];
10870
10871          if (!key2) return pathVal;
10872          if (pathVal == null) return undefined;
10873          pathVal = pathVal[key2];
10874
10875          if (!key3) return pathVal;
10876          if (pathVal == null) return undefined;
10877          pathVal = pathVal[key3];
10878
10879          if (!key4) return pathVal;
10880          if (pathVal == null) return undefined;
10881          pathVal = pathVal[key4];
10882
10883          return pathVal;
10884        }
10885      : function cspSafePromiseEnabledGetter(scope, locals) {
10886          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10887              promise;
10888
10889          if (pathVal == null) return pathVal;
10890
10891          pathVal = pathVal[key0];
10892          if (pathVal && pathVal.then) {
10893            promiseWarning(fullExp);
10894            if (!("$$v" in pathVal)) {
10895              promise = pathVal;
10896              promise.$$v = undefined;
10897              promise.then(function(val) { promise.$$v = val; });
10898            }
10899            pathVal = pathVal.$$v;
10900          }
10901
10902          if (!key1) return pathVal;
10903          if (pathVal == null) return undefined;
10904          pathVal = pathVal[key1];
10905          if (pathVal && pathVal.then) {
10906            promiseWarning(fullExp);
10907            if (!("$$v" in pathVal)) {
10908              promise = pathVal;
10909              promise.$$v = undefined;
10910              promise.then(function(val) { promise.$$v = val; });
10911            }
10912            pathVal = pathVal.$$v;
10913          }
10914
10915          if (!key2) return pathVal;
10916          if (pathVal == null) return undefined;
10917          pathVal = pathVal[key2];
10918          if (pathVal && pathVal.then) {
10919            promiseWarning(fullExp);
10920            if (!("$$v" in pathVal)) {
10921              promise = pathVal;
10922              promise.$$v = undefined;
10923              promise.then(function(val) { promise.$$v = val; });
10924            }
10925            pathVal = pathVal.$$v;
10926          }
10927
10928          if (!key3) return pathVal;
10929          if (pathVal == null) return undefined;
10930          pathVal = pathVal[key3];
10931          if (pathVal && pathVal.then) {
10932            promiseWarning(fullExp);
10933            if (!("$$v" in pathVal)) {
10934              promise = pathVal;
10935              promise.$$v = undefined;
10936              promise.then(function(val) { promise.$$v = val; });
10937            }
10938            pathVal = pathVal.$$v;
10939          }
10940
10941          if (!key4) return pathVal;
10942          if (pathVal == null) return undefined;
10943          pathVal = pathVal[key4];
10944          if (pathVal && pathVal.then) {
10945            promiseWarning(fullExp);
10946            if (!("$$v" in pathVal)) {
10947              promise = pathVal;
10948              promise.$$v = undefined;
10949              promise.then(function(val) { promise.$$v = val; });
10950            }
10951            pathVal = pathVal.$$v;
10952          }
10953          return pathVal;
10954        };
10955}
10956
10957function simpleGetterFn1(key0, fullExp) {
10958  ensureSafeMemberName(key0, fullExp);
10959
10960  return function simpleGetterFn1(scope, locals) {
10961    if (scope == null) return undefined;
10962    return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10963  };
10964}
10965
10966function simpleGetterFn2(key0, key1, fullExp) {
10967  ensureSafeMemberName(key0, fullExp);
10968  ensureSafeMemberName(key1, fullExp);
10969
10970  return function simpleGetterFn2(scope, locals) {
10971    if (scope == null) return undefined;
10972    scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10973    return scope == null ? undefined : scope[key1];
10974  };
10975}
10976
10977function getterFn(path, options, fullExp) {
10978  // Check whether the cache has this getter already.
10979  // We can use hasOwnProperty directly on the cache because we ensure,
10980  // see below, that the cache never stores a path called 'hasOwnProperty'
10981  if (getterFnCache.hasOwnProperty(path)) {
10982    return getterFnCache[path];
10983  }
10984
10985  var pathKeys = path.split('.'),
10986      pathKeysLength = pathKeys.length,
10987      fn;
10988
10989  // When we have only 1 or 2 tokens, use optimized special case closures.
10990  // http://jsperf.com/angularjs-parse-getter/6
10991  if (!options.unwrapPromises && pathKeysLength === 1) {
10992    fn = simpleGetterFn1(pathKeys[0], fullExp);
10993  } else if (!options.unwrapPromises && pathKeysLength === 2) {
10994    fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
10995  } else if (options.csp) {
10996    if (pathKeysLength < 6) {
10997      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
10998                          options);
10999    } else {
11000      fn = function(scope, locals) {
11001        var i = 0, val;
11002        do {
11003          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
11004                                pathKeys[i++], fullExp, options)(scope, locals);
11005
11006          locals = undefined; // clear after first iteration
11007          scope = val;
11008        } while (i < pathKeysLength);
11009        return val;
11010      };
11011    }
11012  } else {
11013    var code = 'var p;\n';
11014    forEach(pathKeys, function(key, index) {
11015      ensureSafeMemberName(key, fullExp);
11016      code += 'if(s == null) return undefined;\n' +
11017              's='+ (index
11018                      // we simply dereference 's' on any .dot notation
11019                      ? 's'
11020                      // but if we are first then we check locals first, and if so read it first
11021                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
11022              (options.unwrapPromises
11023                ? 'if (s && s.then) {\n' +
11024                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
11025                  ' if (!("$$v" in s)) {\n' +
11026                    ' p=s;\n' +
11027                    ' p.$$v = undefined;\n' +
11028                    ' p.then(function(v) {p.$$v=v;});\n' +
11029                    '}\n' +
11030                  ' s=s.$$v\n' +
11031                '}\n'
11032                : '');
11033    });
11034    code += 'return s;';
11035
11036    /* jshint -W054 */
11037    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
11038    /* jshint +W054 */
11039    evaledFnGetter.toString = valueFn(code);
11040    fn = options.unwrapPromises ? function(scope, locals) {
11041      return evaledFnGetter(scope, locals, promiseWarning);
11042    } : evaledFnGetter;
11043  }
11044
11045  // Only cache the value if it's not going to mess up the cache object
11046  // This is more performant that using Object.prototype.hasOwnProperty.call
11047  if (path !== 'hasOwnProperty') {
11048    getterFnCache[path] = fn;
11049  }
11050  return fn;
11051}
11052
11053///////////////////////////////////
11054
11055/**
11056 * @ngdoc service
11057 * @name $parse
11058 * @kind function
11059 *
11060 * @description
11061 *
11062 * Converts Angular {@link guide/expression expression} into a function.
11063 *
11064 * ```js
11065 *   var getter = $parse('user.name');
11066 *   var setter = getter.assign;
11067 *   var context = {user:{name:'angular'}};
11068 *   var locals = {user:{name:'local'}};
11069 *
11070 *   expect(getter(context)).toEqual('angular');
11071 *   setter(context, 'newValue');
11072 *   expect(context.user.name).toEqual('newValue');
11073 *   expect(getter(context, locals)).toEqual('local');
11074 * ```
11075 *
11076 *
11077 * @param {string} expression String expression to compile.
11078 * @returns {function(context, locals)} a function which represents the compiled expression:
11079 *
11080 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11081 *      are evaluated against (typically a scope object).
11082 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11083 *      `context`.
11084 *
11085 *    The returned function also has the following properties:
11086 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
11087 *        literal.
11088 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
11089 *        constant literals.
11090 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
11091 *        set to a function to change its value on the given context.
11092 *
11093 */
11094
11095
11096/**
11097 * @ngdoc provider
11098 * @name $parseProvider
11099 * @kind function
11100 *
11101 * @description
11102 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
11103 *  service.
11104 */
11105function $ParseProvider() {
11106  var cache = {};
11107
11108  var $parseOptions = {
11109    csp: false,
11110    unwrapPromises: false,
11111    logPromiseWarnings: true
11112  };
11113
11114
11115  /**
11116   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11117   *
11118   * @ngdoc method
11119   * @name $parseProvider#unwrapPromises
11120   * @description
11121   *
11122   * **This feature is deprecated, see deprecation notes below for more info**
11123   *
11124   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
11125   * found at any part of the expression. In other words, if set to true, the expression will always
11126   * result in a non-promise value.
11127   *
11128   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
11129   * the fulfillment value is used in place of the promise while evaluating the expression.
11130   *
11131   * **Deprecation notice**
11132   *
11133   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
11134   * dichotomy between data access in templates (accessed as raw values) and controller code
11135   * (accessed as promises).
11136   *
11137   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
11138   * the model access there.
11139   *
11140   * Other downsides of automatic promise unwrapping:
11141   *
11142   * - when building components it's often desirable to receive the raw promises
11143   * - adds complexity and slows down expression evaluation
11144   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
11145   *   generated
11146   * - makes IDE auto-completion and tool support hard
11147   *
11148   * **Warning Logs**
11149   *
11150   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
11151   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
11152   * `$parseProvider.logPromiseWarnings(false)` api.
11153   *
11154   *
11155   * @param {boolean=} value New value.
11156   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11157   *                         setter.
11158   */
11159  this.unwrapPromises = function(value) {
11160    if (isDefined(value)) {
11161      $parseOptions.unwrapPromises = !!value;
11162      return this;
11163    } else {
11164      return $parseOptions.unwrapPromises;
11165    }
11166  };
11167
11168
11169  /**
11170   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11171   *
11172   * @ngdoc method
11173   * @name $parseProvider#logPromiseWarnings
11174   * @description
11175   *
11176   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11177   *
11178   * The default is set to `true`.
11179   *
11180   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11181   *
11182   * @param {boolean=} value New value.
11183   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11184   *                         setter.
11185   */
11186 this.logPromiseWarnings = function(value) {
11187    if (isDefined(value)) {
11188      $parseOptions.logPromiseWarnings = value;
11189      return this;
11190    } else {
11191      return $parseOptions.logPromiseWarnings;
11192    }
11193  };
11194
11195
11196  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
11197    $parseOptions.csp = $sniffer.csp;
11198
11199    promiseWarning = function promiseWarningFn(fullExp) {
11200      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11201      promiseWarningCache[fullExp] = true;
11202      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11203          'Automatic unwrapping of promises in Angular expressions is deprecated.');
11204    };
11205
11206    return function(exp) {
11207      var parsedExpression;
11208
11209      switch (typeof exp) {
11210        case 'string':
11211
11212          if (cache.hasOwnProperty(exp)) {
11213            return cache[exp];
11214          }
11215
11216          var lexer = new Lexer($parseOptions);
11217          var parser = new Parser(lexer, $filter, $parseOptions);
11218          parsedExpression = parser.parse(exp);
11219
11220          if (exp !== 'hasOwnProperty') {
11221            // Only cache the value if it's not going to mess up the cache object
11222            // This is more performant that using Object.prototype.hasOwnProperty.call
11223            cache[exp] = parsedExpression;
11224          }
11225
11226          return parsedExpression;
11227
11228        case 'function':
11229          return exp;
11230
11231        default:
11232          return noop;
11233      }
11234    };
11235  }];
11236}
11237
11238/**
11239 * @ngdoc service
11240 * @name $q
11241 * @requires $rootScope
11242 *
11243 * @description
11244 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
11245 *
11246 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11247 * interface for interacting with an object that represents the result of an action that is
11248 * performed asynchronously, and may or may not be finished at any given point in time.
11249 *
11250 * From the perspective of dealing with error handling, deferred and promise APIs are to
11251 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11252 *
11253 * ```js
11254 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11255 *   // are available in the current lexical scope (they could have been injected or passed in).
11256 *
11257 *   function asyncGreet(name) {
11258 *     var deferred = $q.defer();
11259 *
11260 *     setTimeout(function() {
11261 *       deferred.notify('About to greet ' + name + '.');
11262 *
11263 *       if (okToGreet(name)) {
11264 *         deferred.resolve('Hello, ' + name + '!');
11265 *       } else {
11266 *         deferred.reject('Greeting ' + name + ' is not allowed.');
11267 *       }
11268 *     }, 1000);
11269 *
11270 *     return deferred.promise;
11271 *   }
11272 *
11273 *   var promise = asyncGreet('Robin Hood');
11274 *   promise.then(function(greeting) {
11275 *     alert('Success: ' + greeting);
11276 *   }, function(reason) {
11277 *     alert('Failed: ' + reason);
11278 *   }, function(update) {
11279 *     alert('Got notification: ' + update);
11280 *   });
11281 * ```
11282 *
11283 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11284 * comes in the way of guarantees that promise and deferred APIs make, see
11285 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11286 *
11287 * Additionally the promise api allows for composition that is very hard to do with the
11288 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11289 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11290 * section on serial or parallel joining of promises.
11291 *
11292 *
11293 * # The Deferred API
11294 *
11295 * A new instance of deferred is constructed by calling `$q.defer()`.
11296 *
11297 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11298 * that can be used for signaling the successful or unsuccessful completion, as well as the status
11299 * of the task.
11300 *
11301 * **Methods**
11302 *
11303 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11304 *   constructed via `$q.reject`, the promise will be rejected instead.
11305 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11306 *   resolving it with a rejection constructed via `$q.reject`.
11307 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11308 *   multiple times before the promise is either resolved or rejected.
11309 *
11310 * **Properties**
11311 *
11312 * - promise – `{Promise}` – promise object associated with this deferred.
11313 *
11314 *
11315 * # The Promise API
11316 *
11317 * A new promise instance is created when a deferred instance is created and can be retrieved by
11318 * calling `deferred.promise`.
11319 *
11320 * The purpose of the promise object is to allow for interested parties to get access to the result
11321 * of the deferred task when it completes.
11322 *
11323 * **Methods**
11324 *
11325 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11326 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11327 *   as soon as the result is available. The callbacks are called with a single argument: the result
11328 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11329 *   provide a progress indication, before the promise is resolved or rejected.
11330 *
11331 *   This method *returns a new promise* which is resolved or rejected via the return value of the
11332 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11333 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11334 *   method.
11335 *
11336 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11337 *
11338 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11339 *   but to do so without modifying the final value. This is useful to release resources or do some
11340 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11341 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11342 *   more information.
11343 *
11344 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11345 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11346 *   make your code IE8 and Android 2.x compatible.
11347 *
11348 * # Chaining promises
11349 *
11350 * Because calling the `then` method of a promise returns a new derived promise, it is easily
11351 * possible to create a chain of promises:
11352 *
11353 * ```js
11354 *   promiseB = promiseA.then(function(result) {
11355 *     return result + 1;
11356 *   });
11357 *
11358 *   // promiseB will be resolved immediately after promiseA is resolved and its value
11359 *   // will be the result of promiseA incremented by 1
11360 * ```
11361 *
11362 * It is possible to create chains of any length and since a promise can be resolved with another
11363 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11364 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11365 * $http's response interceptors.
11366 *
11367 *
11368 * # Differences between Kris Kowal's Q and $q
11369 *
11370 *  There are two main differences:
11371 *
11372 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11373 *   mechanism in angular, which means faster propagation of resolution or rejection into your
11374 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11375 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11376 *   all the important functionality needed for common async tasks.
11377 *
11378 *  # Testing
11379 *
11380 *  ```js
11381 *    it('should simulate promise', inject(function($q, $rootScope) {
11382 *      var deferred = $q.defer();
11383 *      var promise = deferred.promise;
11384 *      var resolvedValue;
11385 *
11386 *      promise.then(function(value) { resolvedValue = value; });
11387 *      expect(resolvedValue).toBeUndefined();
11388 *
11389 *      // Simulate resolving of promise
11390 *      deferred.resolve(123);
11391 *      // Note that the 'then' function does not get called synchronously.
11392 *      // This is because we want the promise API to always be async, whether or not
11393 *      // it got called synchronously or asynchronously.
11394 *      expect(resolvedValue).toBeUndefined();
11395 *
11396 *      // Propagate promise resolution to 'then' functions using $apply().
11397 *      $rootScope.$apply();
11398 *      expect(resolvedValue).toEqual(123);
11399 *    }));
11400 *  ```
11401 */
11402function $QProvider() {
11403
11404  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
11405    return qFactory(function(callback) {
11406      $rootScope.$evalAsync(callback);
11407    }, $exceptionHandler);
11408  }];
11409}
11410
11411
11412/**
11413 * Constructs a promise manager.
11414 *
11415 * @param {function(Function)} nextTick Function for executing functions in the next turn.
11416 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11417 *     debugging purposes.
11418 * @returns {object} Promise manager.
11419 */
11420function qFactory(nextTick, exceptionHandler) {
11421
11422  /**
11423   * @ngdoc method
11424   * @name $q#defer
11425   * @kind function
11426   *
11427   * @description
11428   * Creates a `Deferred` object which represents a task which will finish in the future.
11429   *
11430   * @returns {Deferred} Returns a new instance of deferred.
11431   */
11432  var defer = function() {
11433    var pending = [],
11434        value, deferred;
11435
11436    deferred = {
11437
11438      resolve: function(val) {
11439        if (pending) {
11440          var callbacks = pending;
11441          pending = undefined;
11442          value = ref(val);
11443
11444          if (callbacks.length) {
11445            nextTick(function() {
11446              var callback;
11447              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11448                callback = callbacks[i];
11449                value.then(callback[0], callback[1], callback[2]);
11450              }
11451            });
11452          }
11453        }
11454      },
11455
11456
11457      reject: function(reason) {
11458        deferred.resolve(createInternalRejectedPromise(reason));
11459      },
11460
11461
11462      notify: function(progress) {
11463        if (pending) {
11464          var callbacks = pending;
11465
11466          if (pending.length) {
11467            nextTick(function() {
11468              var callback;
11469              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11470                callback = callbacks[i];
11471                callback[2](progress);
11472              }
11473            });
11474          }
11475        }
11476      },
11477
11478
11479      promise: {
11480        then: function(callback, errback, progressback) {
11481          var result = defer();
11482
11483          var wrappedCallback = function(value) {
11484            try {
11485              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11486            } catch(e) {
11487              result.reject(e);
11488              exceptionHandler(e);
11489            }
11490          };
11491
11492          var wrappedErrback = function(reason) {
11493            try {
11494              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11495            } catch(e) {
11496              result.reject(e);
11497              exceptionHandler(e);
11498            }
11499          };
11500
11501          var wrappedProgressback = function(progress) {
11502            try {
11503              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11504            } catch(e) {
11505              exceptionHandler(e);
11506            }
11507          };
11508
11509          if (pending) {
11510            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11511          } else {
11512            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11513          }
11514
11515          return result.promise;
11516        },
11517
11518        "catch": function(callback) {
11519          return this.then(null, callback);
11520        },
11521
11522        "finally": function(callback) {
11523
11524          function makePromise(value, resolved) {
11525            var result = defer();
11526            if (resolved) {
11527              result.resolve(value);
11528            } else {
11529              result.reject(value);
11530            }
11531            return result.promise;
11532          }
11533
11534          function handleCallback(value, isResolved) {
11535            var callbackOutput = null;
11536            try {
11537              callbackOutput = (callback ||defaultCallback)();
11538            } catch(e) {
11539              return makePromise(e, false);
11540            }
11541            if (callbackOutput && isFunction(callbackOutput.then)) {
11542              return callbackOutput.then(function() {
11543                return makePromise(value, isResolved);
11544              }, function(error) {
11545                return makePromise(error, false);
11546              });
11547            } else {
11548              return makePromise(value, isResolved);
11549            }
11550          }
11551
11552          return this.then(function(value) {
11553            return handleCallback(value, true);
11554          }, function(error) {
11555            return handleCallback(error, false);
11556          });
11557        }
11558      }
11559    };
11560
11561    return deferred;
11562  };
11563
11564
11565  var ref = function(value) {
11566    if (value && isFunction(value.then)) return value;
11567    return {
11568      then: function(callback) {
11569        var result = defer();
11570        nextTick(function() {
11571          result.resolve(callback(value));
11572        });
11573        return result.promise;
11574      }
11575    };
11576  };
11577
11578
11579  /**
11580   * @ngdoc method
11581   * @name $q#reject
11582   * @kind function
11583   *
11584   * @description
11585   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11586   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11587   * a promise chain, you don't need to worry about it.
11588   *
11589   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11590   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11591   * a promise error callback and you want to forward the error to the promise derived from the
11592   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11593   * `reject`.
11594   *
11595   * ```js
11596   *   promiseB = promiseA.then(function(result) {
11597   *     // success: do something and resolve promiseB
11598   *     //          with the old or a new result
11599   *     return result;
11600   *   }, function(reason) {
11601   *     // error: handle the error if possible and
11602   *     //        resolve promiseB with newPromiseOrValue,
11603   *     //        otherwise forward the rejection to promiseB
11604   *     if (canHandle(reason)) {
11605   *      // handle the error and recover
11606   *      return newPromiseOrValue;
11607   *     }
11608   *     return $q.reject(reason);
11609   *   });
11610   * ```
11611   *
11612   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11613   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11614   */
11615  var reject = function(reason) {
11616    var result = defer();
11617    result.reject(reason);
11618    return result.promise;
11619  };
11620
11621  var createInternalRejectedPromise = function(reason) {
11622    return {
11623      then: function(callback, errback) {
11624        var result = defer();
11625        nextTick(function() {
11626          try {
11627            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11628          } catch(e) {
11629            result.reject(e);
11630            exceptionHandler(e);
11631          }
11632        });
11633        return result.promise;
11634      }
11635    };
11636  };
11637
11638
11639  /**
11640   * @ngdoc method
11641   * @name $q#when
11642   * @kind function
11643   *
11644   * @description
11645   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11646   * This is useful when you are dealing with an object that might or might not be a promise, or if
11647   * the promise comes from a source that can't be trusted.
11648   *
11649   * @param {*} value Value or a promise
11650   * @returns {Promise} Returns a promise of the passed value or promise
11651   */
11652  var when = function(value, callback, errback, progressback) {
11653    var result = defer(),
11654        done;
11655
11656    var wrappedCallback = function(value) {
11657      try {
11658        return (isFunction(callback) ? callback : defaultCallback)(value);
11659      } catch (e) {
11660        exceptionHandler(e);
11661        return reject(e);
11662      }
11663    };
11664
11665    var wrappedErrback = function(reason) {
11666      try {
11667        return (isFunction(errback) ? errback : defaultErrback)(reason);
11668      } catch (e) {
11669        exceptionHandler(e);
11670        return reject(e);
11671      }
11672    };
11673
11674    var wrappedProgressback = function(progress) {
11675      try {
11676        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11677      } catch (e) {
11678        exceptionHandler(e);
11679      }
11680    };
11681
11682    nextTick(function() {
11683      ref(value).then(function(value) {
11684        if (done) return;
11685        done = true;
11686        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11687      }, function(reason) {
11688        if (done) return;
11689        done = true;
11690        result.resolve(wrappedErrback(reason));
11691      }, function(progress) {
11692        if (done) return;
11693        result.notify(wrappedProgressback(progress));
11694      });
11695    });
11696
11697    return result.promise;
11698  };
11699
11700
11701  function defaultCallback(value) {
11702    return value;
11703  }
11704
11705
11706  function defaultErrback(reason) {
11707    return reject(reason);
11708  }
11709
11710
11711  /**
11712   * @ngdoc method
11713   * @name $q#all
11714   * @kind function
11715   *
11716   * @description
11717   * Combines multiple promises into a single promise that is resolved when all of the input
11718   * promises are resolved.
11719   *
11720   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11721   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11722   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11723   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11724   *   with the same rejection value.
11725   */
11726  function all(promises) {
11727    var deferred = defer(),
11728        counter = 0,
11729        results = isArray(promises) ? [] : {};
11730
11731    forEach(promises, function(promise, key) {
11732      counter++;
11733      ref(promise).then(function(value) {
11734        if (results.hasOwnProperty(key)) return;
11735        results[key] = value;
11736        if (!(--counter)) deferred.resolve(results);
11737      }, function(reason) {
11738        if (results.hasOwnProperty(key)) return;
11739        deferred.reject(reason);
11740      });
11741    });
vendor: 4,332 bytes, lines 11742-11875
11742
11743    if (counter === 0) {
11744      deferred.resolve(results);
11745    }
11746
11747    return deferred.promise;
11748  }
11749
11750  return {
11751    defer: defer,
11752    reject: reject,
11753    when: when,
11754    all: all
11755  };
11756}
11757
11758function $$RAFProvider(){ //rAF
11759  this.$get = ['$window', '$timeout', function($window, $timeout) {
11760    var requestAnimationFrame = $window.requestAnimationFrame ||
11761                                $window.webkitRequestAnimationFrame ||
11762                                $window.mozRequestAnimationFrame;
11763
11764    var cancelAnimationFrame = $window.cancelAnimationFrame ||
11765                               $window.webkitCancelAnimationFrame ||
11766                               $window.mozCancelAnimationFrame ||
11767                               $window.webkitCancelRequestAnimationFrame;
11768
11769    var rafSupported = !!requestAnimationFrame;
11770    var raf = rafSupported
11771      ? function(fn) {
11772          var id = requestAnimationFrame(fn);
11773          return function() {
11774            cancelAnimationFrame(id);
11775          };
11776        }
11777      : function(fn) {
11778          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
11779          return function() {
11780            $timeout.cancel(timer);
11781          };
11782        };
11783
11784    raf.supported = rafSupported;
11785
11786    return raf;
11787  }];
11788}
11789
11790/**
11791 * DESIGN NOTES
11792 *
11793 * The design decisions behind the scope are heavily favored for speed and memory consumption.
11794 *
11795 * The typical use of scope is to watch the expressions, which most of the time return the same
11796 * value as last time so we optimize the operation.
11797 *
11798 * Closures construction is expensive in terms of speed as well as memory:
11799 *   - No closures, instead use prototypical inheritance for API
11800 *   - Internal state needs to be stored on scope directly, which means that private state is
11801 *     exposed as $$____ properties
11802 *
11803 * Loop operations are optimized by using while(count--) { ... }
11804 *   - this means that in order to keep the same order of execution as addition we have to add
11805 *     items to the array at the beginning (unshift) instead of at the end (push)
11806 *
11807 * Child scopes are created and removed often
11808 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11809 *
11810 * There are few watches then a lot of observers. This is why you don't want the observer to be
11811 * implemented in the same way as watch. Watch requires return of initialization function which
11812 * are expensive to construct.
11813 */
11814
11815
11816/**
11817 * @ngdoc provider
11818 * @name $rootScopeProvider
11819 * @description
11820 *
11821 * Provider for the $rootScope service.
11822 */
11823
11824/**
11825 * @ngdoc method
11826 * @name $rootScopeProvider#digestTtl
11827 * @description
11828 *
11829 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11830 * assuming that the model is unstable.
11831 *
11832 * The current default is 10 iterations.
11833 *
11834 * In complex applications it's possible that the dependencies between `$watch`s will result in
11835 * several digest iterations. However if an application needs more than the default 10 digest
11836 * iterations for its model to stabilize then you should investigate what is causing the model to
11837 * continuously change during the digest.
11838 *
11839 * Increasing the TTL could have performance implications, so you should not change it without
11840 * proper justification.
11841 *
11842 * @param {number} limit The number of digest iterations.
11843 */
11844
11845
11846/**
11847 * @ngdoc service
11848 * @name $rootScope
11849 * @description
11850 *
11851 * Every application has a single root {@link ng.$rootScope.Scope scope}.
11852 * All other scopes are descendant scopes of the root scope. Scopes provide separation
11853 * between the model and the view, via a mechanism for watching the model for changes.
11854 * They also provide an event emission/broadcast and subscription facility. See the
11855 * {@link guide/scope developer guide on scopes}.
11856 */
11857function $RootScopeProvider(){
11858  var TTL = 10;
11859  var $rootScopeMinErr = minErr('$rootScope');
11860  var lastDirtyWatch = null;
11861
11862  this.digestTtl = function(value) {
11863    if (arguments.length) {
11864      TTL = value;
11865    }
11866    return TTL;
11867  };
11868
11869  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11870      function( $injector,   $exceptionHandler,   $parse,   $browser) {
11871
11872    /**
11873     * @ngdoc type
11874     * @name $rootScope.Scope
11875     *
11876     * @description
11877     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11878     * {@link auto.$injector $injector}. Child scopes are created using the
11879     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
11880     * compiled HTML template is executed.)
11881     *
11882     * Here is a simple scope snippet to show how you can interact with the scope.
11883     * ```html
11884     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11885     * ```
11886     *
11887     * # Inheritance
11888     * A scope can inherit from a parent scope, as in this example:
11889     * ```js
11890         var parent = $rootScope;
11891         var child = parent.$new();
11892
11893         parent.salutation = "Hello";
11894         child.name = "World";
11895         expect(child.salutation).toEqual('Hello');
11896
11897         child.salutation = "Welcome";
11898         expect(child.salutation).toEqual('Welcome');
11899         expect(parent.salutation).toEqual('Hello');
11900     * ```
11901     *
11902     *
11903     * @param {Object.<string, function()>=} providers Map of service factory which need to be
11904     *                                       provided for the current scope. Defaults to {@link ng}.
11905     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11906     *                              append/override services provided by `providers`. This is handy
11907     *                              when unit-testing and having the need to override a default
11908     *                              service.
11909     * @returns {Object} Newly created scope.
11910     *
11911     */
11912    function Scope() {
11913      this.$id = nextUid();
11914      this.$$phase = this.$parent = this.$$watchers =
11915                     this.$$nextSibling = this.$$prevSibling =
11916                     this.$$childHead = this.$$childTail = null;
11917      this['this'] = this.$root =  this;
11918      this.$$destroyed = false;
11919      this.$$asyncQueue = [];
11920      this.$$postDigestQueue = [];
11921      this.$$listeners = {};
11922      this.$$listenerCount = {};
11923      this.$$isolateBindings = {};
11924    }
11925
11926    /**
11927     * @ngdoc property
11928     * @name $rootScope.Scope#$id
11929     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11930     *   debugging.
11931     */
11932
11933
11934    Scope.prototype = {
11935      constructor: Scope,
11936      /**
11937       * @ngdoc method
11938       * @name $rootScope.Scope#$new
11939       * @kind function
11940       *
11941       * @description
11942       * Creates a new child {@link ng.$rootScope.Scope scope}.
11943       *
11944       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
11945       * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
11946       * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
11947       *
11948       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
11949       * desired for the scope and its child scopes to be permanently detached from the parent and
11950       * thus stop participating in model change detection and listener notification by invoking.
11951       *
11952       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
11953       *         parent scope. The scope is isolated, as it can not see parent scope properties.
11954       *         When creating widgets, it is useful for the widget to not accidentally read parent
11955       *         state.
11956       *
11957       * @returns {Object} The newly created child scope.
11958       *
11959       */
11960      $new: function(isolate) {
11961        var ChildScope,
11962            child;
11963
11964        if (isolate) {
11965          child = new Scope();
11966          child.$root = this.$root;
11967          // ensure that there is just one async queue per $rootScope and its children
11968          child.$$asyncQueue = this.$$asyncQueue;
11969          child.$$postDigestQueue = this.$$postDigestQueue;
11970        } else {
11971          // Only create a child scope class if somebody asks for one,
11972          // but cache it to allow the VM to optimize lookups.
11973          if (!this.$$childScopeClass) {
11974            this.$$childScopeClass = function() {
11975              this.$$watchers = this.$$nextSibling =
11976                  this.$$childHead = this.$$childTail = null;
11977              this.$$listeners = {};
11978              this.$$listenerCount = {};
11979              this.$id = nextUid();
11980              this.$$childScopeClass = null;
11981            };
11982            this.$$childScopeClass.prototype = this;
11983          }
11984          child = new this.$$childScopeClass();
11985        }
11986        child['this'] = child;
11987        child.$parent = this;
11988        child.$$prevSibling = this.$$childTail;
11989        if (this.$$childHead) {
11990          this.$$childTail.$$nextSibling = child;
11991          this.$$childTail = child;
11992        } else {
11993          this.$$childHead = this.$$childTail = child;
11994        }
11995        return child;
11996      },
11997
11998      /**
11999       * @ngdoc method
12000       * @name $rootScope.Scope#$watch
12001       * @kind function
12002       *
12003       * @description
12004       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
12005       *
12006       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
12007       *   $digest()} and should return the value that will be watched. (Since
12008       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
12009       *   `watchExpression` can execute multiple times per
12010       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
12011       * - The `listener` is called only when the value from the current `watchExpression` and the
12012       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
12013       *   see below). Inequality is determined according to reference inequality,
12014       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
12015       *    via the `!==` Javascript operator, unless `objectEquality == true`
12016       *   (see next point)
12017       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
12018       *   according to the {@link angular.equals} function. To save the value of the object for
12019       *   later comparison, the {@link angular.copy} function is used. This therefore means that
12020       *   watching complex objects will have adverse memory and performance implications.
12021       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
12022       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
12023       *   iteration limit is 10 to prevent an infinite loop deadlock.
12024       *
12025       *
12026       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
12027       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
12028       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
12029       * change is detected, be prepared for multiple calls to your listener.)
12030       *
12031       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
12032       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
12033       * watcher. In rare cases, this is undesirable because the listener is called when the result
12034       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
12035       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
12036       * listener was called due to initialization.
12037       *
12038       * The example below contains an illustration of using a function as your $watch listener
12039       *
12040       *
12041       * # Example
12042       * ```js
12043           // let's assume that scope was dependency injected as the $rootScope
12044           var scope = $rootScope;
12045           scope.name = 'misko';
12046           scope.counter = 0;
12047
12048           expect(scope.counter).toEqual(0);
12049           scope.$watch('name', function(newValue, oldValue) {
12050             scope.counter = scope.counter + 1;
12051           });
12052           expect(scope.counter).toEqual(0);
12053
12054           scope.$digest();
12055           // the listener is always called during the first $digest loop after it was registered
12056           expect(scope.counter).toEqual(1);
12057
12058           scope.$digest();
12059           // but now it will not be called unless the value changes
12060           expect(scope.counter).toEqual(1);
12061
12062           scope.name = 'adam';
12063           scope.$digest();
12064           expect(scope.counter).toEqual(2);
12065
12066
12067
12068           // Using a listener function
12069           var food;
12070           scope.foodCounter = 0;
12071           expect(scope.foodCounter).toEqual(0);
12072           scope.$watch(
12073             // This is the listener function
12074             function() { return food; },
12075             // This is the change handler
12076             function(newValue, oldValue) {
12077               if ( newValue !== oldValue ) {
12078                 // Only increment the counter if the value changed
12079                 scope.foodCounter = scope.foodCounter + 1;
12080               }
12081             }
12082           );
12083           // No digest has been run so the counter will be zero
12084           expect(scope.foodCounter).toEqual(0);
12085
12086           // Run the digest but since food has not changed count will still be zero
12087           scope.$digest();
12088           expect(scope.foodCounter).toEqual(0);
12089
12090           // Update food and run digest.  Now the counter will increment
12091           food = 'cheeseburger';
12092           scope.$digest();
12093           expect(scope.foodCounter).toEqual(1);
12094
12095       * ```
12096       *
12097       *
12098       *
12099       * @param {(function()|string)} watchExpression Expression that is evaluated on each
12100       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
12101       *    a call to the `listener`.
12102       *
12103       *    - `string`: Evaluated as {@link guide/expression expression}
12104       *    - `function(scope)`: called with current `scope` as a parameter.
12105       * @param {(function()|string)=} listener Callback called whenever the return value of
12106       *   the `watchExpression` changes.
12107       *
12108       *    - `string`: Evaluated as {@link guide/expression expression}
12109       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
12110       *      parameters.
12111       *
12112       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
12113       *     comparing for reference equality.
12114       * @returns {function()} Returns a deregistration function for this listener.
12115       */
12116      $watch: function(watchExp, listener, objectEquality) {
12117        var scope = this,
12118            get = compileToFn(watchExp, 'watch'),
12119            array = scope.$$watchers,
12120            watcher = {
12121              fn: listener,
12122              last: initWatchVal,
12123              get: get,
12124              exp: watchExp,
12125              eq: !!objectEquality
12126            };
12127
12128        lastDirtyWatch = null;
12129
12130        // in the case user pass string, we need to compile it, do we really need this ?
12131        if (!isFunction(listener)) {
12132          var listenFn = compileToFn(listener || noop, 'listener');
12133          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
12134        }
12135
12136        if (typeof watchExp == 'string' && get.constant) {
12137          var originalFn = watcher.fn;
12138          watcher.fn = function(newVal, oldVal, scope) {
12139            originalFn.call(this, newVal, oldVal, scope);
12140            arrayRemove(array, watcher);
12141          };
12142        }
12143
12144        if (!array) {
12145          array = scope.$$watchers = [];
12146        }
12147        // we use unshift since we use a while loop in $digest for speed.
12148        // the while loop reads in reverse order.
12149        array.unshift(watcher);
12150
12151        return function deregisterWatch() {
12152          arrayRemove(array, watcher);
12153          lastDirtyWatch = null;
12154        };
12155      },
12156
12157
12158      /**
12159       * @ngdoc method
12160       * @name $rootScope.Scope#$watchCollection
12161       * @kind function
12162       *
12163       * @description
12164       * Shallow watches the properties of an object and fires whenever any of the properties change
12165       * (for arrays, this implies watching the array items; for object maps, this implies watching
12166       * the properties). If a change is detected, the `listener` callback is fired.
12167       *
12168       * - The `obj` collection is observed via standard $watch operation and is examined on every
12169       *   call to $digest() to see if any items have been added, removed, or moved.
12170       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
12171       *   adding, removing, and moving items belonging to an object or array.
12172       *
12173       *
12174       * # Example
12175       * ```js
12176          $scope.names = ['igor', 'matias', 'misko', 'james'];
12177          $scope.dataCount = 4;
12178
12179          $scope.$watchCollection('names', function(newNames, oldNames) {
12180            $scope.dataCount = newNames.length;
12181          });
12182
12183          expect($scope.dataCount).toEqual(4);
12184          $scope.$digest();
12185
12186          //still at 4 ... no changes
12187          expect($scope.dataCount).toEqual(4);
12188
12189          $scope.names.pop();
12190          $scope.$digest();
12191
12192          //now there's been a change
12193          expect($scope.dataCount).toEqual(3);
12194       * ```
12195       *
12196       *
12197       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12198       *    expression value should evaluate to an object or an array which is observed on each
12199       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12200       *    collection will trigger a call to the `listener`.
12201       *
12202       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12203       *    when a change is detected.
12204       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12205       *    - The `oldCollection` object is a copy of the former collection data.
12206       *      Due to performance considerations, the`oldCollection` value is computed only if the
12207       *      `listener` function declares two or more arguments.
12208       *    - The `scope` argument refers to the current scope.
12209       *
12210       * @returns {function()} Returns a de-registration function for this listener. When the
12211       *    de-registration function is executed, the internal watch operation is terminated.
12212       */
12213      $watchCollection: function(obj, listener) {
12214        var self = this;
12215        // the current value, updated on each dirty-check run
12216        var newValue;
12217        // a shallow copy of the newValue from the last dirty-check run,
12218        // updated to match newValue during dirty-check run
12219        var oldValue;
12220        // a shallow copy of the newValue from when the last change happened
12221        var veryOldValue;
12222        // only track veryOldValue if the listener is asking for it
12223        var trackVeryOldValue = (listener.length > 1);
12224        var changeDetected = 0;
12225        var objGetter = $parse(obj);
12226        var internalArray = [];
12227        var internalObject = {};
12228        var initRun = true;
12229        var oldLength = 0;
12230
12231        function $watchCollectionWatch() {
12232          newValue = objGetter(self);
12233          var newLength, key;
12234
12235          if (!isObject(newValue)) { // if primitive
12236            if (oldValue !== newValue) {
12237              oldValue = newValue;
12238              changeDetected++;
12239            }
12240          } else if (isArrayLike(newValue)) {
12241            if (oldValue !== internalArray) {
12242              // we are transitioning from something which was not an array into array.
12243              oldValue = internalArray;
12244              oldLength = oldValue.length = 0;
12245              changeDetected++;
12246            }
12247
12248            newLength = newValue.length;
12249
12250            if (oldLength !== newLength) {
12251              // if lengths do not match we need to trigger change notification
12252              changeDetected++;
12253              oldValue.length = oldLength = newLength;
12254            }
12255            // copy the items to oldValue and look for changes.
12256            for (var i = 0; i < newLength; i++) {
12257              var bothNaN = (oldValue[i] !== oldValue[i]) &&
12258                  (newValue[i] !== newValue[i]);
12259              if (!bothNaN && (oldValue[i] !== newValue[i])) {
12260                changeDetected++;
12261                oldValue[i] = newValue[i];
12262              }
12263            }
12264          } else {
12265            if (oldValue !== internalObject) {
12266              // we are transitioning from something which was not an object into object.
12267              oldValue = internalObject = {};
12268              oldLength = 0;
12269              changeDetected++;
12270            }
12271            // copy the items to oldValue and look for changes.
12272            newLength = 0;
12273            for (key in newValue) {
12274              if (newValue.hasOwnProperty(key)) {
12275                newLength++;
12276                if (oldValue.hasOwnProperty(key)) {
12277                  if (oldValue[key] !== newValue[key]) {
12278                    changeDetected++;
12279                    oldValue[key] = newValue[key];
12280                  }
12281                } else {
12282                  oldLength++;
12283                  oldValue[key] = newValue[key];
12284                  changeDetected++;
12285                }
12286              }
12287            }
12288            if (oldLength > newLength) {
12289              // we used to have more keys, need to find them and destroy them.
12290              changeDetected++;
12291              for(key in oldValue) {
12292                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12293                  oldLength--;
12294                  delete oldValue[key];
12295                }
12296              }
12297            }
12298          }
12299          return changeDetected;
12300        }
12301
12302        function $watchCollectionAction() {
12303          if (initRun) {
12304            initRun = false;
12305            listener(newValue, newValue, self);
12306          } else {
12307            listener(newValue, veryOldValue, self);
12308          }
12309
12310          // make a copy for the next time a collection is changed
12311          if (trackVeryOldValue) {
12312            if (!isObject(newValue)) {
12313              //primitive
12314              veryOldValue = newValue;
12315            } else if (isArrayLike(newValue)) {
12316              veryOldValue = new Array(newValue.length);
12317              for (var i = 0; i < newValue.length; i++) {
12318                veryOldValue[i] = newValue[i];
12319              }
12320            } else { // if object
12321              veryOldValue = {};
12322              for (var key in newValue) {
12323                if (hasOwnProperty.call(newValue, key)) {
12324                  veryOldValue[key] = newValue[key];
12325                }
12326              }
12327            }
12328          }
12329        }
12330
12331        return this.$watch($watchCollectionWatch, $watchCollectionAction);
12332      },
12333
12334      /**
12335       * @ngdoc method
12336       * @name $rootScope.Scope#$digest
12337       * @kind function
12338       *
12339       * @description
12340       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12341       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12342       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12343       * until no more listeners are firing. This means that it is possible to get into an infinite
12344       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12345       * iterations exceeds 10.
12346       *
12347       * Usually, you don't call `$digest()` directly in
12348       * {@link ng.directive:ngController controllers} or in
12349       * {@link ng.$compileProvider#directive directives}.
12350       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12351       * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12352       *
12353       * If you want to be notified whenever `$digest()` is called,
12354       * you can register a `watchExpression` function with
12355       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12356       *
12357       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12358       *
12359       * # Example
12360       * ```js
12361           var scope = ...;
12362           scope.name = 'misko';
12363           scope.counter = 0;
12364
12365           expect(scope.counter).toEqual(0);
12366           scope.$watch('name', function(newValue, oldValue) {
12367             scope.counter = scope.counter + 1;
12368           });
12369           expect(scope.counter).toEqual(0);
12370
12371           scope.$digest();
12372           // the listener is always called during the first $digest loop after it was registered
12373           expect(scope.counter).toEqual(1);
12374
12375           scope.$digest();
12376           // but now it will not be called unless the value changes
12377           expect(scope.counter).toEqual(1);
12378
12379           scope.name = 'adam';
12380           scope.$digest();
12381           expect(scope.counter).toEqual(2);
12382       * ```
12383       *
12384       */
12385      $digest: function() {
12386        var watch, value, last,
12387            watchers,
12388            asyncQueue = this.$$asyncQueue,
12389            postDigestQueue = this.$$postDigestQueue,
12390            length,
12391            dirty, ttl = TTL,
12392            next, current, target = this,
12393            watchLog = [],
12394            logIdx, logMsg, asyncTask;
12395
12396        beginPhase('$digest');
12397
12398        lastDirtyWatch = null;
12399
12400        do { // "while dirty" loop
12401          dirty = false;
12402          current = target;
12403
12404          while(asyncQueue.length) {
12405            try {
12406              asyncTask = asyncQueue.shift();
12407              asyncTask.scope.$eval(asyncTask.expression);
12408            } catch (e) {
12409              clearPhase();
12410              $exceptionHandler(e);
12411            }
12412            lastDirtyWatch = null;
12413          }
12414
12415          traverseScopesLoop:
12416          do { // "traverse the scopes" loop
12417            if ((watchers = current.$$watchers)) {
12418              // process our watches
12419              length = watchers.length;
12420              while (length--) {
12421                try {
12422                  watch = watchers[length];
12423                  // Most common watches are on primitives, in which case we can short
12424                  // circuit it with === operator, only when === fails do we use .equals
12425                  if (watch) {
12426                    if ((value = watch.get(current)) !== (last = watch.last) &&
12427                        !(watch.eq
12428                            ? equals(value, last)
12429                            : (typeof value === 'number' && typeof last === 'number'
12430                               && isNaN(value) && isNaN(last)))) {
12431                      dirty = true;
12432                      lastDirtyWatch = watch;
12433                      watch.last = watch.eq ? copy(value, null) : value;
12434                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
12435                      if (ttl < 5) {
12436                        logIdx = 4 - ttl;
12437                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
12438                        logMsg = (isFunction(watch.exp))
12439                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12440                            : watch.exp;
12441                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12442                        watchLog[logIdx].push(logMsg);
12443                      }
12444                    } else if (watch === lastDirtyWatch) {
12445                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12446                      // have already been tested.
12447                      dirty = false;
12448                      break traverseScopesLoop;
12449                    }
12450                  }
12451                } catch (e) {
12452                  clearPhase();
12453                  $exceptionHandler(e);
12454                }
12455              }
12456            }
12457
12458            // Insanity Warning: scope depth-first traversal
12459            // yes, this code is a bit crazy, but it works and we have tests to prove it!
12460            // this piece should be kept in sync with the traversal in $broadcast
12461            if (!(next = (current.$$childHead ||
12462                (current !== target && current.$$nextSibling)))) {
12463              while(current !== target && !(next = current.$$nextSibling)) {
12464                current = current.$parent;
12465              }
12466            }
12467          } while ((current = next));
12468
12469          // `break traverseScopesLoop;` takes us to here
12470
12471          if((dirty || asyncQueue.length) && !(ttl--)) {
12472            clearPhase();
12473            throw $rootScopeMinErr('infdig',
12474                '{0} $digest() iterations reached. Aborting!\n' +
12475                'Watchers fired in the last 5 iterations: {1}',
12476                TTL, toJson(watchLog));
12477          }
12478
12479        } while (dirty || asyncQueue.length);
12480
12481        clearPhase();
12482
12483        while(postDigestQueue.length) {
12484          try {
12485            postDigestQueue.shift()();
12486          } catch (e) {
12487            $exceptionHandler(e);
12488          }
12489        }
12490      },
12491
12492
12493      /**
12494       * @ngdoc event
12495       * @name $rootScope.Scope#$destroy
12496       * @eventType broadcast on scope being destroyed
12497       *
12498       * @description
12499       * Broadcasted when a scope and its children are being destroyed.
12500       *
12501       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12502       * clean up DOM bindings before an element is removed from the DOM.
12503       */
12504
12505      /**
12506       * @ngdoc method
12507       * @name $rootScope.Scope#$destroy
12508       * @kind function
12509       *
12510       * @description
12511       * Removes the current scope (and all of its children) from the parent scope. Removal implies
12512       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12513       * propagate to the current scope and its children. Removal also implies that the current
12514       * scope is eligible for garbage collection.
12515       *
12516       * The `$destroy()` is usually used by directives such as
12517       * {@link ng.directive:ngRepeat ngRepeat} for managing the
12518       * unrolling of the loop.
12519       *
12520       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12521       * Application code can register a `$destroy` event handler that will give it a chance to
12522       * perform any necessary cleanup.
12523       *
12524       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12525       * clean up DOM bindings before an element is removed from the DOM.
12526       */
12527      $destroy: function() {
12528        // we can't destroy the root scope or a scope that has been already destroyed
12529        if (this.$$destroyed) return;
12530        var parent = this.$parent;
12531
12532        this.$broadcast('$destroy');
12533        this.$$destroyed = true;
12534        if (this === $rootScope) return;
12535
12536        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12537
12538        // sever all the references to parent scopes (after this cleanup, the current scope should
12539        // not be retained by any of our references and should be eligible for garbage collection)
12540        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12541        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12542        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12543        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12544
12545
12546        // All of the code below is bogus code that works around V8's memory leak via optimized code
12547        // and inline caches.
12548        //
12549        // see:
12550        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12551        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12552        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12553
12554        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12555            this.$$childTail = this.$root = null;
12556
12557        // don't reset these to null in case some async task tries to register a listener/watch/task
12558        this.$$listeners = {};
12559        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12560
12561        // prevent NPEs since these methods have references to properties we nulled out
12562        this.$destroy = this.$digest = this.$apply = noop;
12563        this.$on = this.$watch = function() { return noop; };
12564      },
12565
12566      /**
12567       * @ngdoc method
12568       * @name $rootScope.Scope#$eval
12569       * @kind function
12570       *
12571       * @description
12572       * Executes the `expression` on the current scope and returns the result. Any exceptions in
12573       * the expression are propagated (uncaught). This is useful when evaluating Angular
12574       * expressions.
12575       *
12576       * # Example
12577       * ```js
12578           var scope = ng.$rootScope.Scope();
12579           scope.a = 1;
12580           scope.b = 2;
12581
12582           expect(scope.$eval('a+b')).toEqual(3);
12583           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12584       * ```
12585       *
12586       * @param {(string|function())=} expression An angular expression to be executed.
12587       *
12588       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12589       *    - `function(scope)`: execute the function with the current `scope` parameter.
12590       *
12591       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12592       * @returns {*} The result of evaluating the expression.
12593       */
12594      $eval: function(expr, locals) {
12595        return $parse(expr)(this, locals);
12596      },
12597
12598      /**
12599       * @ngdoc method
12600       * @name $rootScope.Scope#$evalAsync
12601       * @kind function
12602       *
12603       * @description
12604       * Executes the expression on the current scope at a later point in time.
12605       *
12606       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12607       * that:
12608       *
12609       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12610       *     rendering).
12611       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12612       *     `expression` execution.
12613       *
12614       * Any exceptions from the execution of the expression are forwarded to the
12615       * {@link ng.$exceptionHandler $exceptionHandler} service.
12616       *
12617       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12618       * will be scheduled. However, it is encouraged to always call code that changes the model
12619       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12620       *
12621       * @param {(string|function())=} expression An angular expression to be executed.
12622       *
12623       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12624       *    - `function(scope)`: execute the function with the current `scope` parameter.
12625       *
12626       */
12627      $evalAsync: function(expr) {
12628        // if we are outside of an $digest loop and this is the first time we are scheduling async
12629        // task also schedule async auto-flush
12630        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12631          $browser.defer(function() {
12632            if ($rootScope.$$asyncQueue.length) {
12633              $rootScope.$digest();
12634            }
12635          });
12636        }
12637
12638        this.$$asyncQueue.push({scope: this, expression: expr});
12639      },
12640
12641      $$postDigest : function(fn) {
12642        this.$$postDigestQueue.push(fn);
12643      },
12644
12645      /**
12646       * @ngdoc method
12647       * @name $rootScope.Scope#$apply
12648       * @kind function
12649       *
12650       * @description
12651       * `$apply()` is used to execute an expression in angular from outside of the angular
12652       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12653       * Because we are calling into the angular framework we need to perform proper scope life
12654       * cycle of {@link ng.$exceptionHandler exception handling},
12655       * {@link ng.$rootScope.Scope#$digest executing watches}.
12656       *
12657       * ## Life cycle
12658       *
12659       * # Pseudo-Code of `$apply()`
12660       * ```js
12661           function $apply(expr) {
12662             try {
12663               return $eval(expr);
12664             } catch (e) {
12665               $exceptionHandler(e);
12666             } finally {
12667               $root.$digest();
12668             }
12669           }
12670       * ```
12671       *
12672       *
12673       * Scope's `$apply()` method transitions through the following stages:
12674       *
12675       * 1. The {@link guide/expression expression} is executed using the
12676       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12677       * 2. Any exceptions from the execution of the expression are forwarded to the
12678       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12679       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12680       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12681       *
12682       *
12683       * @param {(string|function())=} exp An angular expression to be executed.
12684       *
12685       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12686       *    - `function(scope)`: execute the function with current `scope` parameter.
12687       *
12688       * @returns {*} The result of evaluating the expression.
12689       */
12690      $apply: function(expr) {
12691        try {
12692          beginPhase('$apply');
12693          return this.$eval(expr);
12694        } catch (e) {
12695          $exceptionHandler(e);
12696        } finally {
12697          clearPhase();
12698          try {
12699            $rootScope.$digest();
12700          } catch (e) {
12701            $exceptionHandler(e);
12702            throw e;
12703          }
12704        }
12705      },
12706
12707      /**
12708       * @ngdoc method
12709       * @name $rootScope.Scope#$on
12710       * @kind function
12711       *
12712       * @description
12713       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12714       * discussion of event life cycle.
12715       *
12716       * The event listener function format is: `function(event, args...)`. The `event` object
12717       * passed into the listener has the following attributes:
12718       *
12719       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12720       *     `$broadcast`-ed.
12721       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12722       *   - `name` - `{string}`: name of the event.
12723       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12724       *     further event propagation (available only for events that were `$emit`-ed).
12725       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12726       *     to true.
12727       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12728       *
12729       * @param {string} name Event name to listen on.
12730       * @param {function(event, ...args)} listener Function to call when the event is emitted.
12731       * @returns {function()} Returns a deregistration function for this listener.
12732       */
12733      $on: function(name, listener) {
12734        var namedListeners = this.$$listeners[name];
12735        if (!namedListeners) {
12736          this.$$listeners[name] = namedListeners = [];
12737        }
12738        namedListeners.push(listener);
12739
12740        var current = this;
12741        do {
12742          if (!current.$$listenerCount[name]) {
12743            current.$$listenerCount[name] = 0;
12744          }
12745          current.$$listenerCount[name]++;
12746        } while ((current = current.$parent));
12747
12748        var self = this;
12749        return function() {
12750          namedListeners[indexOf(namedListeners, listener)] = null;
12751          decrementListenerCount(self, 1, name);
12752        };
12753      },
12754
12755
12756      /**
12757       * @ngdoc method
12758       * @name $rootScope.Scope#$emit
12759       * @kind function
12760       *
12761       * @description
12762       * Dispatches an event `name` upwards through the scope hierarchy notifying the
12763       * registered {@link ng.$rootScope.Scope#$on} listeners.
12764       *
12765       * The event life cycle starts at the scope on which `$emit` was called. All
12766       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12767       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12768       * registered listeners along the way. The event will stop propagating if one of the listeners
12769       * cancels it.
12770       *
12771       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12772       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12773       *
12774       * @param {string} name Event name to emit.
12775       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12776       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
12777       */
12778      $emit: function(name, args) {
12779        var empty = [],
12780            namedListeners,
12781            scope = this,
12782            stopPropagation = false,
12783            event = {
12784              name: name,
12785              targetScope: scope,
12786              stopPropagation: function() {stopPropagation = true;},
12787              preventDefault: function() {
12788                event.defaultPrevented = true;
12789              },
12790              defaultPrevented: false
12791            },
12792            listenerArgs = concat([event], arguments, 1),
12793            i, length;
12794
12795        do {
12796          namedListeners = scope.$$listeners[name] || empty;
12797          event.currentScope = scope;
12798          for (i=0, length=namedListeners.length; i<length; i++) {
12799
12800            // if listeners were deregistered, defragment the array
12801            if (!namedListeners[i]) {
12802              namedListeners.splice(i, 1);
12803              i--;
12804              length--;
12805              continue;
12806            }
12807            try {
12808              //allow all listeners attached to the current scope to run
12809              namedListeners[i].apply(null, listenerArgs);
12810            } catch (e) {
12811              $exceptionHandler(e);
12812            }
12813          }
12814          //if any listener on the current scope stops propagation, prevent bubbling
12815          if (stopPropagation) return event;
12816          //traverse upwards
12817          scope = scope.$parent;
12818        } while (scope);
12819
12820        return event;
12821      },
12822
12823
12824      /**
12825       * @ngdoc method
12826       * @name $rootScope.Scope#$broadcast
12827       * @kind function
12828       *
12829       * @description
12830       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12831       * registered {@link ng.$rootScope.Scope#$on} listeners.
12832       *
12833       * The event life cycle starts at the scope on which `$broadcast` was called. All
12834       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12835       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12836       * scope and calls all registered listeners along the way. The event cannot be canceled.
12837       *
12838       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12839       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12840       *
12841       * @param {string} name Event name to broadcast.
12842       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12843       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
12844       */
12845      $broadcast: function(name, args) {
12846        var target = this,
12847            current = target,
12848            next = target,
12849            event = {
12850              name: name,
12851              targetScope: target,
12852              preventDefault: function() {
12853                event.defaultPrevented = true;
12854              },
12855              defaultPrevented: false
12856            },
12857            listenerArgs = concat([event], arguments, 1),
12858            listeners, i, length;
12859
12860        //down while you can, then up and next sibling or up and next sibling until back at root
12861        while ((current = next)) {
12862          event.currentScope = current;
12863          listeners = current.$$listeners[name] || [];
12864          for (i=0, length = listeners.length; i<length; i++) {
12865            // if listeners were deregistered, defragment the array
12866            if (!listeners[i]) {
12867              listeners.splice(i, 1);
12868              i--;
12869              length--;
12870              continue;
12871            }
12872
12873            try {
12874              listeners[i].apply(null, listenerArgs);
12875            } catch(e) {
12876              $exceptionHandler(e);
12877            }
12878          }
12879
12880          // Insanity Warning: scope depth-first traversal
12881          // yes, this code is a bit crazy, but it works and we have tests to prove it!
12882          // this piece should be kept in sync with the traversal in $digest
12883          // (though it differs due to having the extra check for $$listenerCount)
12884          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12885              (current !== target && current.$$nextSibling)))) {
12886            while(current !== target && !(next = current.$$nextSibling)) {
12887              current = current.$parent;
12888            }
12889          }
12890        }
12891
12892        return event;
12893      }
12894    };
12895
12896    var $rootScope = new Scope();
12897
12898    return $rootScope;
12899
12900
12901    function beginPhase(phase) {
12902      if ($rootScope.$$phase) {
12903        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12904      }
12905
12906      $rootScope.$$phase = phase;
12907    }
12908
12909    function clearPhase() {
12910      $rootScope.$$phase = null;
12911    }
12912
12913    function compileToFn(exp, name) {
12914      var fn = $parse(exp);
12915      assertArgFn(fn, name);
12916      return fn;
12917    }
12918
12919    function decrementListenerCount(current, count, name) {
12920      do {
12921        current.$$listenerCount[name] -= count;
12922
12923        if (current.$$listenerCount[name] === 0) {
12924          delete current.$$listenerCount[name];
12925        }
12926      } while ((current = current.$parent));
12927    }
12928
12929    /**
12930     * function used as an initial value for watchers.
12931     * because it's unique we can easily tell it apart from other values
12932     */
12933    function initWatchVal() {}
12934  }];
12935}
12936
12937/**
12938 * @description
12939 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
12940 */
12941function $$SanitizeUriProvider() {
12942  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12943    imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12944
12945  /**
12946   * @description
12947   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12948   * urls during a[href] sanitization.
12949   *
12950   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12951   *
12952   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12953   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12954   * regular expression. If a match is found, the original url is 
12954written into the dom. Otherwise,
12955   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12956   *
12957   * @param {RegExp=} regexp New regexp to whitelist urls with.
12958   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12959   *    chaining otherwise.
12960   */
12961  this.aHrefSanitizationWhitelist = function(regexp) {
12962    if (isDefined(regexp)) {
12963      aHrefSanitizationWhitelist = regexp;
12964      return this;
12965    }
12966    return aHrefSanitizationWhitelist;
12967  };
12968
12969
12970  /**
12971   * @description
12972   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12973   * urls during img[src] sanitization.
12974   *
12975   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12976   *
12977   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12978   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12979   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12980   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12981   *
12982   * @param {RegExp=} regexp New regexp to whitelist urls with.
12983   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12984   *    chaining otherwise.
12985   */
12986  this.imgSrcSanitizationWhitelist = function(regexp) {
12987    if (isDefined(regexp)) {
12988      imgSrcSanitizationWhitelist = regexp;
12989      return this;
12990    }
12991    return imgSrcSanitizationWhitelist;
12992  };
12993
12994  this.$get = function() {
12995    return function sanitizeUri(uri, isImage) {
12996      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12997      var normalizedVal;
12998      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12999      if (!msie || msie >= 8 ) {
13000        normalizedVal = urlResolve(uri).href;
13001        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
13002          return 'unsafe:'+normalizedVal;
13003        }
13004      }
13005      return uri;
13006    };
13007  };
13008}
13009
13010var $sceMinErr = minErr('$sce');
13011
13012var SCE_CONTEXTS = {
13013  HTML: 'html',
13014  CSS: 'css',
13015  URL: 'url',
13016  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
13017  // url.  (e.g. ng-include, script src, templateUrl)
13018  RESOURCE_URL: 'resourceUrl',
13019  JS: 'js'
13020};
13021
13022// Helper functions follow.
13023
13024// Copied from:
13025// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
13026// Prereq: s is a string.
13027function escapeForRegexp(s) {
13028  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
13029           replace(/\x08/g, '\\x08');
13030}
13031
13032
13033function adjustMatcher(matcher) {
13034  if (matcher === 'self') {
13035    return matcher;
13036  } else if (isString(matcher)) {
13037    // Strings match exactly except for 2 wildcards - '*' and '**'.
13038    // '*' matches any character except those from the set ':/.?&'.
13039    // '**' matches any character (like .* in a RegExp).
13040    // More than 2 *'s raises an error as it's ill defined.
13041    if (matcher.indexOf('***') > -1) {
13042      throw $sceMinErr('iwcard',
13043          'Illegal sequence *** in string matcher.  String: {0}', matcher);
13044    }
13045    matcher = escapeForRegexp(matcher).
13046                  replace('\\*\\*', '.*').
13047                  replace('\\*', '[^:/.?&;]*');
13048    return new RegExp('^' + matcher + '$');
13049  } else if (isRegExp(matcher)) {
13050    // The only other type of matcher allowed is a Regexp.
13051    // Match entire URL / disallow partial matches.
13052    // Flags are reset (i.e. no global, ignoreCase or multiline)
13053    return new RegExp('^' + matcher.source + '$');
13054  } else {
13055    throw $sceMinErr('imatcher',
13056        'Matchers may only be "self", string patterns or RegExp objects');
13057  }
13058}
13059
13060
13061function adjustMatchers(matchers) {
13062  var adjustedMatchers = [];
13063  if (isDefined(matchers)) {
13064    forEach(matchers, function(matcher) {
13065      adjustedMatchers.push(adjustMatcher(matcher));
13066    });
13067  }
13068  return adjustedMatchers;
13069}
13070
13071
13072/**
13073 * @ngdoc service
13074 * @name $sceDelegate
13075 * @kind function
13076 *
13077 * @description
13078 *
13079 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
13080 * Contextual Escaping (SCE)} services to AngularJS.
13081 *
13082 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
13083 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
13084 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
13085 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
13086 * work because `$sce` delegates to `$sceDelegate` for these operations.
13087 *
13088 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
13089 *
13090 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
13091 * can override it completely to change the behavior of `$sce`, the common case would
13092 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
13093 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
13094 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
13095 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
13096 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13097 */
13098
13099/**
13100 * @ngdoc provider
13101 * @name $sceDelegateProvider
13102 * @description
13103 *
13104 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
13105 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
13106 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
13107 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
13108 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13109 *
13110 * For the general details about this service in Angular, read the main page for {@link ng.$sce
13111 * Strict Contextual Escaping (SCE)}.
13112 *
13113 * **Example**:  Consider the following case. <a name="example"></a>
13114 *
13115 * - your app is hosted at url `http://myapp.example.com/`
13116 * - but some of your templates are hosted on other domains you control such as
13117 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
13118 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
13119 *
13120 * Here is what a secure configuration for this scenario might look like:
13121 *
13122 * <pre class="prettyprint">
13123 *    angular.module('myApp', []).config(function($sceDelegateProvider) {
13124 *      $sceDelegateProvider.resourceUrlWhitelist([
13125 *        // Allow same origin resource loads.
13126 *        'self',
13127 *        // Allow loading from our assets domain.  Notice the difference between * and **.
13128 *        'http://srv*.assets.example.com/**']);
13129 *
13130 *      // The blacklist overrides the whitelist so the open redirect here is blocked.
13131 *      $sceDelegateProvider.resourceUrlBlacklist([
13132 *        'http://myapp.example.com/clickThru**']);
13133 *      });
13134 * </pre>
13135 */
13136
13137function $SceDelegateProvider() {
13138  this.SCE_CONTEXTS = SCE_CONTEXTS;
13139
13140  // Resource URLs can also be trusted by policy.
13141  var resourceUrlWhitelist = ['self'],
13142      resourceUrlBlacklist = [];
13143
13144  /**
13145   * @ngdoc method
13146   * @name $sceDelegateProvider#resourceUrlWhitelist
13147   * @kind function
13148   *
13149   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
13150   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13151   *     changes to the array are ignored.
13152   *
13153   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13154   *     allowed in this array.
13155   *
13156   *     Note: **an empty whitelist array will block all URLs**!
13157   *
13158   * @return {Array} the currently set whitelist array.
13159   *
13160   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
13161   * same origin resource requests.
13162   *
13163   * @description
13164   * Sets/Gets the whitelist of trusted resource URLs.
13165   */
13166  this.resourceUrlWhitelist = function (value) {
13167    if (arguments.length) {
13168      resourceUrlWhitelist = adjustMatchers(value);
13169    }
13170    return resourceUrlWhitelist;
13171  };
13172
13173  /**
13174   * @ngdoc method
13175   * @name $sceDelegateProvider#resourceUrlBlacklist
13176   * @kind function
13177   *
13178   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
13179   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13180   *     changes to the array are ignored.
13181   *
13182   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13183   *     allowed in this array.
13184   *
13185   *     The typical usage for the blacklist is to **block
13186   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13187   *     these would otherwise be trusted but actually return content from the redirected domain.
13188   *
vendor: 4,741 bytes, lines 13189-13316
13189   *     Finally, **the blacklist overrides the whitelist** and has the final say.
13190   *
13191   * @return {Array} the currently set blacklist array.
13192   *
13193   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13194   * is no blacklist.)
13195   *
13196   * @description
13197   * Sets/Gets the blacklist of trusted resource URLs.
13198   */
13199
13200  this.resourceUrlBlacklist = function (value) {
13201    if (arguments.length) {
13202      resourceUrlBlacklist = adjustMatchers(value);
13203    }
13204    return resourceUrlBlacklist;
13205  };
13206
13207  this.$get = ['$injector', function($injector) {
13208
13209    var htmlSanitizer = function htmlSanitizer(html) {
13210      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13211    };
13212
13213    if ($injector.has('$sanitize')) {
13214      htmlSanitizer = $injector.get('$sanitize');
13215    }
13216
13217
13218    function matchUrl(matcher, parsedUrl) {
13219      if (matcher === 'self') {
13220        return urlIsSameOrigin(parsedUrl);
13221      } else {
13222        // definitely a regex.  See adjustMatchers()
13223        return !!matcher.exec(parsedUrl.href);
13224      }
13225    }
13226
13227    function isResourceUrlAllowedByPolicy(url) {
13228      var parsedUrl = urlResolve(url.toString());
13229      var i, n, allowed = false;
13230      // Ensure that at least one item from the whitelist allows this url.
13231      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13232        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13233          allowed = true;
13234          break;
13235        }
13236      }
13237      if (allowed) {
13238        // Ensure that no item from the blacklist blocked this url.
13239        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13240          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13241            allowed = false;
13242            break;
13243          }
13244        }
13245      }
13246      return allowed;
13247    }
13248
13249    function generateHolderType(Base) {
13250      var holderType = function TrustedValueHolderType(trustedValue) {
13251        this.$$unwrapTrustedValue = function() {
13252          return trustedValue;
13253        };
13254      };
13255      if (Base) {
13256        holderType.prototype = new Base();
13257      }
13258      holderType.prototype.valueOf = function sceValueOf() {
13259        return this.$$unwrapTrustedValue();
13260      };
13261      holderType.prototype.toString = function sceToString() {
13262        return this.$$unwrapTrustedValue().toString();
13263      };
13264      return holderType;
13265    }
13266
13267    var trustedValueHolderBase = generateHolderType(),
13268        byType = {};
13269
13270    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13271    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13272    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13273    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13274    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13275
13276    /**
13277     * @ngdoc method
13278     * @name $sceDelegate#trustAs
13279     *
13280     * @description
13281     * Returns an object that is trusted by angular for use in specified strict
13282     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13283     * attribute interpolation, any dom event binding attribute interpolation
13284     * such as for onclick,  etc.) that uses the provided value.
13285     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13286     *
13287     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13288     *   resourceUrl, html, js and css.
13289     * @param {*} value The value that that should be considered trusted/safe.
13290     * @returns {*} A value that can be used to stand in for the provided `value` in places
13291     * where Angular expects a $sce.trustAs() return value.
13292     */
13293    function trustAs(type, trustedValue) {
13294      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13295      if (!Constructor) {
13296        throw $sceMinErr('icontext',
13297            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13298            type, trustedValue);
13299      }
13300      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13301        return trustedValue;
13302      }
13303      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13304      // mutable objects, we ensure here that the value passed in is actually a string.
13305      if (typeof trustedValue !== 'string') {
13306        throw $sceMinErr('itype',
13307            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13308            type);
13309      }
13310      return new Constructor(trustedValue);
13311    }
13312
13313    /**
13314     * @ngdoc method
13315     * @name $sceDelegate#valueOf
13316     *
13317     * @description
13318     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13319     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13320     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13321     *
13322     * If the passed parameter is not a value that had been returned by {@link
13323     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13324     *
13325     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13326     *      call or anything else.
13327     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13328     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13329     *     `value` unchanged.
13330     */
13331    function valueOf(maybeTrusted) {
13332      if (maybeTrusted instanceof trustedValueHolderBase) {
13333        return maybeTrusted.$$unwrapTrustedValue();
13334      } else {
13335        return maybeTrusted;
13336      }
13337    }
13338
13339    /**
13340     * @ngdoc method
13341     * @name $sceDelegate#getTrusted
13342     *
13343     * @description
13344     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13345     * returns the originally supplied value if the queried context type is a supertype of the
13346     * created type.  If this condition isn't satisfied, throws an exception.
13347     *
13348     * @param {string} type The kind of context in which this value is to be used.
13349     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13350     *     `$sceDelegate.trustAs`} call.
13351     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13352     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13353     */
13354    function getTrusted(type, maybeTrusted) {
13355      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13356        return maybeTrusted;
13357      }
13358      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13359      if (constructor && maybeTrusted instanceof constructor) {
13360        return maybeTrusted.$$unwrapTrustedValue();
13361      }
13362      // If we get here, then we may only take one of two actions.
13363      // 1. sanitize the value for the requested type, or
13364      // 2. throw an exception.
13365      if (type === SCE_CONTEXTS.RESOURCE_URL) {
13366        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13367          return maybeTrusted;
13368        } else {
13369          throw $sceMinErr('insecurl',
13370              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13371              maybeTrusted.toString());
13372        }
13373      } else if (type === SCE_CONTEXTS.HTML) {
13374        return htmlSanitizer(maybeTrusted);
13375      }
13376      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13377    }
13378
13379    return { trustAs: trustAs,
13380             getTrusted: getTrusted,
13381             valueOf: valueOf };
13382  }];
13383}
13384
13385
13386/**
13387 * @ngdoc provider
13388 * @name $sceProvider
13389 * @description
13390 *
13391 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13392 * -   enable/disable Strict Contextual Escaping (SCE) in a module
13393 * -   override the default implementation with a custom delegate
13394 *
13395 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13396 */
13397
13398/* jshint maxlen: false*/
13399
13400/**
13401 * @ngdoc service
13402 * @name $sce
13403 * @kind function
13404 *
13405 * @description
13406 *
13407 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13408 *
13409 * # Strict Contextual Escaping
13410 *
13411 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13412 * contexts to result in a value that is marked as safe to use for that context.  One example of
13413 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13414 * to these contexts as privileged or SCE contexts.
13415 *
13416 * As of version 1.2, Angular ships with SCE enabled by default.
13417 *
13418 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13419 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13420 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13421 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13422 * to the top of your HTML document.
13423 *
13424 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13425 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13426 *
13427 * Here's an example of a binding in a privileged context:
13428 *
13429 * <pre class="prettyprint">
13430 *     <input ng-model="userHtml">
13431 *     <div ng-bind-html="userHtml">
13432 * </pre>
13433 *
13434 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13435 * disabled, this application allows the user to render arbitrary HTML into the DIV.
13436 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13437 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13438 * security vulnerabilities.)
13439 *
13440 * For the case of HTML, you might use a library, either on the client side, or on the server side,
13441 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13442 *
13443 * How would you ensure that every place that used these types of bindings was bound to a value that
13444 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13445 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13446 * properties/fields and forgot to update the binding to the sanitized value?
13447 *
13448 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13449 * determine that something explicitly says it's safe to use a value for binding in that
13450 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13451 * for those values that you can easily tell are safe - because they were received from your server,
13452 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13453 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13454 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13455 *
13456 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13457 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13458 * obtain values that will be accepted by SCE / privileged contexts.
13459 *
13460 *
13461 * ## How does it work?
13462 *
13463 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13464 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13465 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13466 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13467 *
13468 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13469 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13470 * simplified):
13471 *
13472 * <pre class="prettyprint">
13473 *   var ngBindHtmlDirective = ['$sce', function($sce) {
13474 *     return function(scope, element, attr) {
13475 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13476 *         element.html(value || '');
13477 *       });
13478 *     };
13479 *   }];
13480 * </pre>
13481 *
13482 * ## Impact on loading templates
13483 *
13484 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13485 * `templateUrl`'s specified by {@link guide/directive directives}.
13486 *
13487 * By default, Angular only loads templates from the same domain and protocol as the application
13488 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13489 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13490 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13491 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13492 *
13493 * *Please note*:
13494 * The browser's
13495 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13496 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13497 * policy apply in addition to this and may further restrict whether the template is successfully
13498 * loaded.  This means that without the right CORS policy, loading templates from a different domain
13499 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13500 * browsers.
13501 *
13502 * ## This feels like too much overhead for the developer?
13503 *
13504 * It's important to remember that SCE only applies to interpolation expressions.
13505 *
13506 * If your expressions are constant literals, they're automatically trusted and you don't need to
13507 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13508 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13509 *
13510 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13511 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13512 *
13513 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13514 * templates in `ng-include` from your application's domain without having to even know about SCE.
13515 * It blocks loading templates from other domains or loading templates over http from an https
13516 * served document.  You can change these by setting your own custom {@link
13517 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13518 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13519 *
13520 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13521 * application that's secure and can be audited to verify that with much more ease than bolting
13522 * security onto an application later.
13523 *
13524 * <a name="contexts"></a>
13525 * ## What trusted context types are supported?
13526 *
13527 * | Context             | Notes          |
13528 * |---------------------|----------------|
13529 * | `$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. |
13530 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13531 * | `$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. |
13532 * | `$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. |
13533 * | `$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. |
13534 *
13535 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13536 *
13537 *  Each element in these arrays must be one of the following:
13538 *
13539 *  - **'self'**
13540 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13541 *      domain** as the application document using the **same protocol**.
13542 *  - **String** (except the special value `'self'`)
13543 *    - The string is matched against the full *normalized / absolute URL* of the resource
13544 *      being tested (substring matches are not good enough.)
13545 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13546 *      match themselves.
13547 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13548 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13549 *      in a whitelist.
13550 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13551 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13552 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13553 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
13554 *      http://foo.example.com/templates/**).
13555 *  - **RegExp** (*see caveat below*)
13556 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13557 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13558 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13559 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13560 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13561 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13562 *      is highly recommended to use the string patterns and only fall back to regular expressions
13563 *      if they as a last resort.
13564 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13565 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13566 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13567 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13568 *    - If you are generating your JavaScript from some other templating engine (not
13569 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13570 *      remember to escape your regular expression (and be aware that you might need more than
13571 *      one level of escaping depending on your templating engine and the way you interpolated
13572 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13573 *      enough before coding your own.  e.g. Ruby has
13574 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13575 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13576 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13577 *      Closure library's [goog.string.regExpEscape(s)](
13578 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13579 *
13580 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13581 *
13582 * ## Show me an example using SCE.
13583 *
13584 * @example
13585<example module="mySceApp" deps="angular-sanitize.js">
13586<file name="index.html">
13587  <div ng-controller="myAppController as myCtrl">
13588    <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13589    <b>User comments</b><br>
13590    By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13591    $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13592    exploit.
13593    <div class="well">
13594      <div ng-repeat="userComment in myCtrl.userComments">
13595        <b>{{userComment.name}}</b>:
13596        <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13597        <br>
13598      </div>
13599    </div>
13600  </div>
13601</file>
13602
13603<file name="script.js">
13604  var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13605
13606  mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13607    var self = this;
13608    $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13609      self.userComments = userComments;
13610    });
13611    self.explicitlyTrustedHtml = $sce.trustAsHtml(
13612        '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13613        'sanitization.&quot;">Hover over this text.</span>');
13614  });
13615</file>
13616
13617<file name="test_data.json">
13618[
13619  { "name": "Alice",
13620    "htmlComment":
13621        "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13622  },
13623  { "name": "Bob",
13624    "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13625  }
13626]
13627</file>
13628
13629<file name="protractor.js" type="protractor">
13630  describe('SCE doc demo', function() {
13631    it('should sanitize untrusted values', function() {
13632      expect(element(by.css('.htmlComment')).getInnerHtml())
13633          .toBe('<span>Is <i>anyone</i> reading this?</span>');
13634    });
13635
13636    it('should NOT sanitize explicitly trusted values', function() {
13637      expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13638          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13639          'sanitization.&quot;">Hover over this text.</span>');
13640    });
13641  });
13642</file>
13643</example>
13644 *
13645 *
13646 *
13647 * ## Can I disable SCE completely?
13648 *
13649 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13650 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13651 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13652 * for cases where you have a lot of existing code that was written before SCE was introduced and
13653 * you're migrating them a module at a time.
13654 *
13655 * That said, here's how you can completely disable SCE:
13656 *
13657 * <pre class="prettyprint">
13658 *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13659 *     // Completely disable SCE.  For demonstration purposes only!
13660 *     // Do not use in new projects.
13661 *     $sceProvider.enabled(false);
13662 *   });
13663 * </pre>
13664 *
13665 */
13666/* jshint maxlen: 100 */
13667
13668function $SceProvider() {
13669  var enabled = true;
13670
13671  /**
13672   * @ngdoc method
13673   * @name $sceProvider#enabled
13674   * @kind function
13675   *
13676   * @param {boolean=} value If provided, then enables/disables SCE.
13677   * @return {boolean} true if SCE is enabled, false otherwise.
13678   *
13679   * @description
13680   * Enables/disables SCE and returns the current value.
13681   */
13682  this.enabled = function (value) {
13683    if (arguments.length) {
13684      enabled = !!value;
13685    }
13686    return enabled;
13687  };
13688
13689
13690  /* Design notes on the default implementation for SCE.
13691   *
13692   * The API contract for the SCE delegate
13693   * -------------------------------------
13694   * The SCE delegate object must provide the following 3 methods:
13695   *
13696   * - trustAs(contextEnum, value)
13697   *     This method is used to tell the SCE service that the provided value is OK to use in the
13698   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13699   *     getTrusted() for a compatible contextEnum and return this value.
13700   *
13701   * - valueOf(value)
13702   *     For values that were not produced by trustAs(), return them as is.  For values that were
13703   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13704   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13705   *     such a value.
13706   *
13707   * - getTrusted(contextEnum, value)
13708   *     This function should return the a value that is safe to use in the context specified by
13709   *     contextEnum or throw and exception otherwise.
13710   *
13711   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13712   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13713   * instance, an implementation could maintain a registry of all trusted objects by context.  In
13714   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13715   * return the same object passed in if it was found in the registry under a compatible context or
13716   * throw an exception otherwise.  An implementation might only wrap values some of the time based
13717   * on some criteria.  getTrusted() might return a value and not throw an exception for special
13718   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13719   *
13720   *
13721   * A note on the inheritance model for SCE contexts
13722   * ------------------------------------------------
13723   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13724   * is purely an implementation details.
13725   *
13726   * The contract is simply this:
13727   *
13728   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13729   *     will also succeed.
13730   *
13731   * Inheritance happens to capture this in a natural way.  In some future, we
13732   * may not use inheritance anymore.  That is OK because no code outside of
13733   * sce.js and sceSpecs.js would need to be aware of this detail.
13734   */
13735
13736  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13737                $parse,   $sniffer,   $sceDelegate) {
13738    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13739    // the "expression(javascript expression)" syntax which is insecure.
13740    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13741      throw $sceMinErr('iequirks',
13742        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13743        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13744        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13745    }
13746
13747    var sce = shallowCopy(SCE_CONTEXTS);
13748
13749    /**
13750     * @ngdoc method
13751     * @name $sce#isEnabled
13752     * @kind function
13753     *
13754     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13755     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13756     *
13757     * @description
13758     * Returns a boolean indicating if SCE is enabled.
13759     */
13760    sce.isEnabled = function () {
13761      return enabled;
13762    };
13763    sce.trustAs = $sceDelegate.trustAs;
13764    sce.getTrusted = $sceDelegate.getTrusted;
13765    sce.valueOf = $sceDelegate.valueOf;
13766
13767    if (!enabled) {
13768      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13769      sce.valueOf = identity;
13770    }
13771
13772    /**
13773     * @ngdoc method
13774     * @name $sce#parseAs
13775     *
13776     * @description
13777     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13778     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13779     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
13780     * *result*)}
13781     *
13782     * @param {string} type The kind of SCE context in which this result will be used.
13783     * @param {string} expression String expression to compile.
13784     * @returns {function(context, locals)} a function which represents the compiled expression:
13785     *
13786     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13787     *      are evaluated against (typically a scope object).
13788     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13789     *      `context`.
13790     */
13791    sce.parseAs = function sceParseAs(type, expr) {
13792      var parsed = $parse(expr);
13793      if (parsed.literal && parsed.constant) {
13794        return parsed;
13795      } else {
13796        return function sceParseAsTrusted(self, locals) {
13797          return sce.getTrusted(type, parsed(self, locals));
13798        };
13799      }
13800    };
13801
13802    /**
13803     * @ngdoc method
13804     * @name $sce#trustAs
13805     *
13806     * @description
13807     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
13808     * returns an object that is trusted by angular for use in specified strict contextual
13809     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13810     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13811     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13812     * escaping.
13813     *
13814     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13815     *   resource_url, html, js and css.
13816     * @param {*} value The value that that should be considered trusted/safe.
13817     * @returns {*} A value that can be used to stand in for the provided `value` in places
13818     * where Angular expects a $sce.trustAs() return value.
13819     */
13820
13821    /**
13822     * @ngdoc method
13823     * @name $sce#trustAsHtml
13824     *
13825     * @description
13826     * Shorthand method.  `$sce.trustAsHtml(value)` →
13827     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13828     *
13829     * @param {*} value The value to trustAs.
13830     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
13831     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13832     *     only accept expressions that are either literal constants or are the
13833     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13834     */
13835
13836    /**
13837     * @ngdoc method
13838     * @name $sce#trustAsUrl
13839     *
13840     * @description
13841     * Shorthand method.  `$sce.trustAsUrl(value)` →
13842     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13843     *
13844     * @param {*} value The value to trustAs.
13845     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
13846     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13847     *     only accept expressions that are either literal constants or are the
13848     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13849     */
13850
13851    /**
13852     * @ngdoc method
13853     * @name $sce#trustAsResourceUrl
13854     *
13855     * @description
13856     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13857     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13858     *
13859     * @param {*} value The value to trustAs.
13860     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
13861     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13862     *     only accept expressions that are either literal constants or are the return
13863     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
13864     */
13865
13866    /**
13867     * @ngdoc method
13868     * @name $sce#trustAsJs
13869     *
13870     * @description
13871     * Shorthand method.  `$sce.trustAsJs(value)` →
13872     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13873     *
13874     * @param {*} value The value to trustAs.
13875     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
13876     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13877     *     only accept expressions that are either literal constants or are the
13878     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13879     */
13880
13881    /**
13882     * @ngdoc method
13883     * @name $sce#getTrusted
13884     *
13885     * @description
13886     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
13887     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
13888     * originally supplied value if the queried context type is a supertype of the created type.
13889     * If this condition isn't satisfied, throws an exception.
13890     *
13891     * @param {string} type The kind of context in which this value is to be used.
13892     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
13893     *                         call.
13894     * @returns {*} The value the was originally provided to
13895     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
13896     *              Otherwise, throws an exception.
13897     */
13898
13899    /**
13900     * @ngdoc method
13901     * @name $sce#getTrustedHtml
13902     *
13903     * @description
13904     * Shorthand method.  `$sce.getTrustedHtml(value)` →
13905     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13906     *
13907     * @param {*} value The value to pass to `$sce.getTrusted`.
13908     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13909     */
13910
13911    /**
13912     * @ngdoc method
13913     * @name $sce#getTrustedCss
13914     *
13915     * @description
13916     * Shorthand method.  `$sce.getTrustedCss(value)` →
13917     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13918     *
13919     * @param {*} value The value to pass to `$sce.getTrusted`.
13920     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13921     */
13922
13923    /**
13924     * @ngdoc method
13925     * @name $sce#getTrustedUrl
13926     *
13927     * @description
13928     * Shorthand method.  `$sce.getTrustedUrl(value)` →
13929     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13930     *
13931     * @param {*} value The value to pass to `$sce.getTrusted`.
13932     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13933     */
13934
13935    /**
13936     * @ngdoc method
13937     * @name $sce#getTrustedResourceUrl
13938     *
13939     * @description
13940     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
13941     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
13942     *
13943     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
13944     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
13945     */
13946
13947    /**
13948     * @ngdoc method
13949     * @name $sce#getTrustedJs
13950     *
13951     * @description
13952     * Shorthand method.  `$sce.getTrustedJs(value)` →
13953     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
13954     *
13955     * @param {*} value The value to pass to `$sce.getTrusted`.
13956     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
13957     */
13958
13959    /**
13960     * @ngdoc method
13961     * @name $sce#parseAsHtml
13962     *
13963     * @description
13964     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
13965     *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
13966     *
13967     * @param {string} expression String expression to compile.
13968     * @returns {function(context, locals)} a function which represents the compiled expression:
13969     *
13970     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13971     *      are evaluated against (typically a scope object).
13972     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13973     *      `context`.
13974     */
13975
13976    /**
13977     * @ngdoc method
13978     * @name $sce#parseAsCss
13979     *
13980     * @description
13981     * Shorthand method.  `$sce.parseAsCss(value)` →
13982     *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
13983     *
13984     * @param {string} expression String expression to compile.
13985     * @returns {function(context, locals)} a function which represents the compiled expression:
13986     *
13987     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13988     *      are evaluated against (typically a scope object).
13989     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13990     *      `context`.
13991     */
13992
13993    /**
13994     * @ngdoc method
13995     * @name $sce#parseAsUrl
13996     *
13997     * @description
13998     * Shorthand method.  `$sce.parseAsUrl(value)` →
13999     *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
14000     *
14001     * @param {string} expression String expression to compile.
14002     * @returns {function(context, locals)} a function which represents the compiled expression:
14003     *
14004     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14005     *      are evaluated against (typically a scope object).
14006     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14007     *      `context`.
14008     */
14009
14010    /**
14011     * @ngdoc method
14012     * @name $sce#parseAsResourceUrl
14013     *
14014     * @description
14015     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
14016     *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
14017     *
14018     * @param {string} expression String expression to compile.
14019     * @returns {function(context, locals)} a function which represents the compiled expression:
14020     *
14021     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14022     *      are evaluated against (typically a scope object).
14023     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14024     *      `context`.
14025     */
14026
14027    /**
14028     * @ngdoc method
14029     * @name $sce#parseAsJs
14030     *
14031     * @description
14032     * Shorthand method.  `$sce.parseAsJs(value)` →
14033     *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
14034     *
14035     * @param {string} expression String expression to compile.
14036     * @returns {function(context, locals)} a function which represents the compiled expression:
14037     *
14038     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14039     *      are evaluated against (typically a scope object).
14040     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14041     *      `context`.
14042     */
14043
14044    // Shorthand delegations.
14045    var parse = sce.parseAs,
14046        getTrusted = sce.getTrusted,
14047        trustAs = sce.trustAs;
14048
14049    forEach(SCE_CONTEXTS, function (enumValue, name) {
14050      var lName = lowercase(name);
14051      sce[camelCase("parse_as_" + lName)] = function (expr) {
14052        return parse(enumValue, expr);
14053      };
14054      sce[camelCase("get_trusted_" + lName)] = function (value) {
14055        return getTrusted(enumValue, value);
14056      };
14057      sce[camelCase("trust_as_" + lName)] = function (value) {
14058        return trustAs(enumValue, value);
14059      };
14060    });
14061
14062    return sce;
14063  }];
14064}
14065
14066/**
14067 * !!! This is an undocumented "private" service !!!
14068 *
14069 * @name $sniffer
14070 * @requires $window
14071 * @requires $document
14072 *
14073 * @property {boolean} history Does the browser support html5 history api ?
14074 * @property {boolean} hashchange Does the browser support hashchange event ?
14075 * @property {boolean} transitions Does the browser support CSS transition events ?
14076 * @property {boolean} animations Does the browser support CSS animation events ?
14077 *
14078 * @description
14079 * This is very simple implementation of testing browser's features.
14080 */
14081function $SnifferProvider() {
14082  this.$get = ['$window', '$document', function($window, $document) {
14083    var eventSupport = {},
14084        android =
14085          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
14086        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
14087        document = $document[0] || {},
14088        documentMode = document.documentMode,
14089        vendorPrefix,
14090        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
14091        bodyStyle = document.body && document.body.style,
14092        transitions = false,
14093        animations = false,
14094        match;
14095
14096    if (bodyStyle) {
14097      for(var prop in bodyStyle) {
14098        if(match = vendorRegex.exec(prop)) {
14099          vendorPrefix = match[0];
14100          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
14101          break;
14102        }
14103      }
14104
14105      if(!vendorPrefix) {
14106        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
14107      }
14108
14109      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
14110      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
14111
14112      if (android && (!transitions||!animations)) {
14113        transitions = isString(document.body.style.webkitTransition);
14114        animations = isString(document.body.style.webkitAnimation);
14115      }
14116    }
14117
14118
14119    return {
14120      // Android has history.pushState, but it does not update location correctly
14121      // so let's not use the history API at all.
14122      // http://code.google.com/p/android/issues/detail?id=17471
14123      // https://github.com/angular/angular.js/issues/904
14124
14125      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
14126      // so let's not use the history API also
14127      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
14128      // jshint -W018
14129      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
14130      // jshint +W018
14131      hashchange: 'onhashchange' in $window &&
14132                  // IE8 compatible mode lies
14133                  (!documentMode || documentMode > 7),
14134      hasEvent: function(event) {
14135        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
14136        // it. In particular the event is not fired when backspace or delete key are pressed or
14137        // when cut operation is performed.
14138        if (event == 'input' && msie == 9) return false;
14139
14140        if (isUndefined(eventSupport[event])) {
14141          var divElm = document.createElement('div');
14142          eventSupport[event] = 'on' + event in divElm;
14143        }
14144
14145        return eventSupport[event];
14146      },
14147      csp: csp(),
14148      vendorPrefix: vendorPrefix,
14149      transitions : transitions,
14150      animations : animations,
14151      android: android,
14152      msie : msie,
14153      msieDocumentMode: documentMode
14154    };
14155  }];
14156}
14157
14158function $TimeoutProvider() {
14159  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14160       function($rootScope,   $browser,   $q,   $exceptionHandler) {
14161    var deferreds = {};
14162
14163
14164     /**
14165      * @ngdoc service
14166      * @name $timeout
14167      *
14168      * @description
14169      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
14170      * block and delegates any exceptions to
14171      * {@link ng.$exceptionHandler $exceptionHandler} service.
14172      *
14173      * The return value of registering a timeout function is a promise, which will be resolved when
14174      * the timeout is reached and the timeout function is executed.
14175      *
14176      * To cancel a timeout request, call `$timeout.cancel(promise)`.
14177      *
14178      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
14179      * synchronously flush the queue of deferred functions.
14180      *
14181      * @param {function()} fn A function, whose execution should be delayed.
14182      * @param {number=} [delay=0] Delay in milliseconds.
14183      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14184      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14185      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14186      *   promise will be resolved with is the return value of the `fn` function.
14187      *
14188      */
14189    function timeout(fn, delay, invokeApply) {
14190      var deferred = $q.defer(),
14191          promise = deferred.promise,
14192          skipApply = (isDefined(invokeApply) && !invokeApply),
14193          timeoutId;
14194
14195      timeoutId = $browser.defer(function() {
14196        try {
14197          deferred.resolve(fn());
14198        } catch(e) {
14199          deferred.reject(e);
14200          $exceptionHandler(e);
14201        }
14202        finally {
14203          delete deferreds[promise.$$timeoutId];
14204        }
14205
14206        if (!skipApply) $rootScope.$apply();
14207      }, delay);
14208
14209      promise.$$timeoutId = timeoutId;
14210      deferreds[timeoutId] = deferred;
14211
14212      return promise;
14213    }
14214
14215
14216     /**
14217      * @ngdoc method
14218      * @name $timeout#cancel
14219      *
14220      * @description
14221      * Cancels a task associated with the `promise`. As a result of this, the promise will be
14222      * resolved with a rejection.
14223      *
14224      * @param {Promise=} promise Promise returned by the `$timeout` function.
14225      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14226      *   canceled.
14227      */
14228    timeout.cancel = function(promise) {
14229      if (promise && promise.$$timeoutId in deferreds) {
14230        deferreds[promise.$$timeoutId].reject('canceled');
14231        delete deferreds[promise.$$timeoutId];
14232        return $browser.defer.cancel(promise.$$timeoutId);
14233      }
14234      return false;
14235    };
14236
14237    return timeout;
14238  }];
14239}
14240
14241// NOTE:  The usage of window and document instead of $window and $document here is
14242// deliberate.  This service depends on the specific behavior of anchor nodes created by the
14243// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14244// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14245// doesn't know about mocked locations and resolves URLs to the real document - which is
14246// exactly the behavior needed here.  There is little value is mocking these out for this
14247// service.
14248var urlParsingNode = document.createElement("a");
14249var originUrl = urlResolve(window.location.href, true);
14250
14251
14252/**
14253 *
14254 * Implementation Notes for non-IE browsers
14255 * ----------------------------------------
14256 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14257 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14258 * URL will be resolved into an absolute URL in the context of the application document.
14259 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14260 * properties are all populated to reflect the normalized URL.  This approach has wide
14261 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14262 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14263 *
14264 * Implementation Notes for IE
14265 * ---------------------------
14266 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14267 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14268 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14269 * work around that by performing the parsing in a 2nd step by taking a previously normalized
14270 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14271 * properties such as protocol, hostname, port, etc.
14272 *
14273 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14274 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14275 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14276 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14277 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14278 * method and IE < 8 is unsupported.
14279 *
14280 * References:
14281 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14282 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14283 *   http://url.spec.whatwg.org/#urlutils
14284 *   https://github.com/angular/angular.js/pull/2902
14285 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14286 *
14287 * @kind function
14288 * @param {string} url The URL to be parsed.
14289 * @description Normalizes and parses a URL.
14290 * @returns {object} Returns the normalized URL as a dictionary.
14291 *
14292 *   | member name   | Description    |
14293 *   |---------------|----------------|
14294 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14295 *   | protocol      | The protocol including the trailing colon                              |
14296 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14297 *   | search        | The search params, minus the question mark                             |
14298 *   | hash          | The hash string, minus the hash symbol
14299 *   | hostname      | The hostname
14300 *   | port          | The port, without ":"
14301 *   | pathname      | The pathname, beginning with "/"
14302 *
14303 */
14304function urlResolve(url, base) {
14305  var href = url;
14306
14307  if (msie) {
14308    // Normalize before parse.  Refer Implementation Notes on why this is
14309    // done in two steps on IE.
14310    urlParsingNode.setAttribute("href", href);
14311    href = urlParsingNode.href;
14312  }
14313
14314  urlParsingNode.setAttribute('href', href);
14315
14316  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14317  return {
14318    href: urlParsingNode.href,
14319    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14320    host: urlParsingNode.host,
14321    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14322    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14323    hostname: urlParsingNode.hostname,
14324    port: urlParsingNode.port,
14325    pathname: (urlParsingNode.pathname.charAt(0) === '/')
14326      ? urlParsingNode.pathname
14327      : '/' + urlParsingNode.pathname
14328  };
14329}
14330
14331/**
14332 * Parse a request URL and determine whether this is a same-origin request as the application document.
14333 *
14334 * @param {string|object} requestUrl The url of the request as a string that will be resolved
14335 * or a parsed URL object.
14336 * @returns {boolean} Whether the request is for the same origin as the application document.
14337 */
14338function urlIsSameOrigin(requestUrl) {
14339  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14340  return (parsed.protocol === originUrl.protocol &&
14341          parsed.host === originUrl.host);
14342}
14343
14344/**
14345 * @ngdoc service
14346 * @name $window
14347 *
14348 * @description
14349 * A reference to the browser's `window` object. While `window`
14350 * is globally available in JavaScript, it causes testability problems, because
14351 * it is a global variable. In angular we always refer to it through the
14352 * `$window` service, so it may be overridden, removed or mocked for testing.
14353 *
14354 * Expressions, like the one defined for the `ngClick` directive in the example
14355 * below, are evaluated with respect to the current scope.  Therefore, there is
14356 * no risk of inadvertently coding in a dependency on a global value in such an
14357 * expression.
14358 *
14359 * @example
14360   <example>
14361     <file name="index.html">
14362       <script>
14363         function Ctrl($scope, $window) {
14364           $scope.greeting = 'Hello, World!';
14365           $scope.doGreeting = function(greeting) {
14366               $window.alert(greeting);
14367           };
14368         }
14369       </script>
14370       <div ng-controller="Ctrl">
14371         <input type="text" ng-model="greeting" />
14372         <button ng-click="doGreeting(greeting)">ALERT</button>
14373       </div>
14374     </file>
14375     <file name="protractor.js" type="protractor">
14376      it('should display the greeting in the input box', function() {
14377       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14378       // If we click the button it will block the test runner
14379       // element(':button').click();
14380      });
14381     </file>
14382   </example>
14383 */
14384function $WindowProvider(){
14385  this.$get = valueFn(window);
14386}
14387
14388/**
14389 * @ngdoc provider
14390 * @name $filterProvider
14391 * @description
14392 *
14393 * Filters are just functions which transform input to an output. However filters need to be
14394 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14395 * annotated with dependencies and is responsible for creating a filter function.
14396 *
14397 * ```js
14398 *   // Filter registration
14399 *   function MyModule($provide, $filterProvider) {
14400 *     // create a service to demonstrate injection (not always needed)
14401 *     $provide.value('greet', function(name){
14402 *       return 'Hello ' + name + '!';
14403 *     });
14404 *
14405 *     // register a filter factory which uses the
14406 *     // greet service to demonstrate DI.
14407 *     $filterProvider.register('greet', function(greet){
14408 *       // return the filter function which uses the greet service
14409 *       // to generate salutation
14410 *       return function(text) {
14411 *         // filters need to be forgiving so check input validity
14412 *         return text && greet(text) || text;
14413 *       };
14414 *     });
14415 *   }
14416 * ```
14417 *
14418 * The filter function is registered with the `$injector` under the filter name suffix with
14419 * `Filter`.
14420 *
14421 * ```js
14422 *   it('should be the same instance', inject(
14423 *     function($filterProvider) {
14424 *       $filterProvider.register('reverse', function(){
14425 *         return ...;
14426 *       });
14427 *     },
14428 *     function($filter, reverseFilter) {
14429 *       expect($filter('reverse')).toBe(reverseFilter);
14430 *     });
14431 * ```
14432 *
14433 *
14434 * For more information about how angular filters work, and how to create your own filters, see
14435 * {@link guide/filter Filters} in the Angular Developer Guide.
14436 */
14437/**
14438 * @ngdoc method
14439 * @name $filterProvider#register
14440 * @description
14441 * Register filter factory function.
14442 *
14443 * @param {String} name Name of the filter.
14444 * @param {Function} fn The filter factory function which is injectable.
14445 */
14446
14447
14448/**
14449 * @ngdoc service
14450 * @name $filter
14451 * @kind function
14452 * @description
14453 * Filters are used for formatting data displayed to the user.
14454 *
14455 * The general syntax in templates is as follows:
14456 *
14457 *         {{ expression [| filter_name[:parameter_value] ... ] }}
14458 *
14459 * @param {String} name Name of the filter function to retrieve
14460 * @return {Function} the filter function
14461 * @example
14462   <example name="$filter" module="filterExample">
14463     <file name="index.html">
14464       <div ng-controller="MainCtrl">
14465        <h3>{{ originalText }}</h3>
14466        <h3>{{ filteredText }}</h3>
14467       </div>
14468     </file>
14469
14470     <file name="script.js">
14471      angular.module('filterExample', [])
14472      .controller('MainCtrl', function($scope, $filter) {
14473        $scope.originalText = 'hello';
14474        $scope.filteredText = $filter('uppercase')($scope.originalText);
14475      });
14476     </file>
14477   </example>
14478  */
14479$FilterProvider.$inject = ['$provide'];
14480function $FilterProvider($provide) {
14481  var suffix = 'Filter';
14482
14483  /**
14484   * @ngdoc method
14485   * @name $controllerProvider#register
14486   * @param {string|Object} name Name of the filter function, or an object map of filters where
14487   *    the keys are the filter names and the values are the filter factories.
14488   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14489   *    of the registered filter instances.
14490   */
14491  function register(name, factory) {
14492    if(isObject(name)) {
14493      var filters = {};
14494      forEach(name, function(filter, key) {
14495        filters[key] = register(key, filter);
14496      });
14497      return filters;
14498    } else {
14499      return $provide.factory(name + suffix, factory);
14500    }
14501  }
14502  this.register = register;
14503
14504  this.$get = ['$injector', function($injector) {
14505    return function(name) {
14506      return $injector.get(name + suffix);
14507    };
14508  }];
14509
14510  ////////////////////////////////////////
14511
14512  /* global
14513    currencyFilter: false,
14514    dateFilter: false,
14515    filterFilter: false,
14516    jsonFilter: false,
14517    limitToFilter: false,
14518    lowercaseFilter: false,
14519    numberFilter: false,
14520    orderByFilter: false,
14521    uppercaseFilter: false,
14522  */
14523
14524  register('currency', currencyFilter);
14525  register('date', dateFilter);
14526  register('filter', filterFilter);
14527  register('json', jsonFilter);
14528  register('limitTo', limitToFilter);
14529  register('lowercase', lowercaseFilter);
14530  register('number', numberFilter);
14531  register('orderBy', orderByFilter);
14532  register('uppercase', uppercaseFilter);
14533}
14534
14535/**
14536 * @ngdoc filter
14537 * @name filter
14538 * @kind function
14539 *
14540 * @description
14541 * Selects a subset of items from `array` and returns it as a new array.
14542 *
14543 * @param {Array} array The source array.
14544 * @param {string|Object|function()} expression The predicate to be used for selecting items from
14545 *   `array`.
14546 *
14547 *   Can be one of:
14548 *
14549 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14550 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14551 *     will be returned. The predicate can be negated by prefixing the string with `!`.
14552 *
14553 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14554 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14555 *     which have property `name` containing "M" and property `phone` containing "1". A special
14556 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14557 *     property of the object. That's equivalent to the simple substring match with a `string`
14558 *     as described above.
14559 *
14560 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14561 *     called for each element of `array`. The final result is an array of those elements that
14562 *     the predicate returned true for.
14563 *
14564 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14565 *     determining if the expected value (from the filter expression) and actual value (from
14566 *     the object in the array) should be considered a match.
14567 *
14568 *   Can be one of:
14569 *
14570 *   - `function(actual, expected)`:
14571 *     The function will be given the object value and the predicate value to compare and
14572 *     should return true if the item should be included in filtered result.
14573 *
14574 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14575 *     this is essentially strict comparison of expected and actual.
14576 *
14577 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
14578 *     insensitive way.
14579 *
14580 * @example
14581   <example>
14582     <file name="index.html">
14583       <div ng-init="friends = [{name:'John', phone:'555-1276'},
14584                                {name:'Mary', phone:'800-BIG-MARY'},
14585                                {name:'Mike', phone:'555-4321'},
14586                                {name:'Adam', phone:'555-5678'},
14587                                {name:'Julie', phone:'555-8765'},
14588                                {name:'Juliette', phone:'555-5678'}]"></div>
14589
14590       Search: <input ng-model="searchText">
14591       <table id="searchTextResults">
14592         <tr><th>Name</th><th>Phone</th></tr>
14593         <tr ng-repeat="friend in friends | filter:searchText">
14594           <td>{{friend.name}}</td>
14595           <td>{{friend.phone}}</td>
14596         </tr>
14597       </table>
14598       <hr>
14599       Any: <input ng-model="search.$"> <br>
14600       Name only <input ng-model="search.name"><br>
14601       Phone only <input ng-model="search.phone"><br>
14602       Equality <input type="checkbox" ng-model="strict"><br>
14603       <table id="searchObjResults">
14604         <tr><th>Name</th><th>Phone</th></tr>
14605         <tr ng-repeat="friendObj in friends | filter:search:strict">
14606           <td>{{friendObj.name}}</td>
14607           <td>{{friendObj.phone}}</td>
14608         </tr>
14609       </table>
14610     </file>
14611     <file name="protractor.js" type="protractor">
14612       var expectFriendNames = function(expectedNames, key) {
14613         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14614           arr.forEach(function(wd, i) {
14615             expect(wd.getText()).toMatch(expectedNames[i]);
14616           });
14617         });
14618       };
14619
14620       it('should search across all fields when filtering with a string', function() {
14621         var searchText = element(by.model('searchText'));
14622         searchText.clear();
14623         searchText.sendKeys('m');
14624         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14625
14626         searchText.clear();
14627         searchText.sendKeys('76');
14628         expectFriendNames(['John', 'Julie'], 'friend');
14629       });
14630
14631       it('should search in specific fields when filtering with a predicate object', function() {
14632         var searchAny = element(by.model('search.$'));
14633         searchAny.clear();
14634         searchAny.sendKeys('i');
14635         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14636       });
14637       it('should use a equal comparison when comparator is true', function() {
14638         var searchName = element(by.model('search.name'));
14639         var strict = element(by.model('strict'));
14640         searchName.clear();
14641         searchName.sendKeys('Julie');
14642         strict.click();
14643         expectFriendNames(['Julie'], 'friendObj');
14644       });
14645     </file>
14646   </example>
14647 */
14648function filterFilter() {
14649  return function(array, expression, comparator) {
14650    if (!isArray(array)) return array;
14651
14652    var comparatorType = typeof(comparator),
14653        predicates = [];
14654
14655    predicates.check = function(value) {
14656      for (var j = 0; j < predicates.length; j++) {
14657        if(!predicates[j](value)) {
14658          return false;
14659        }
14660      }
14661      return true;
14662    };
14663
14664    if (comparatorType !== 'function') {
14665      if (comparatorType === 'boolean' && comparator) {
14666        comparator = function(obj, text) {
14667          return angular.equals(obj, text);
14668        };
14669      } else {
14670        comparator = function(obj, text) {
14671          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14672            for (var objKey in obj) {
14673              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14674                  comparator(obj[objKey], text[objKey])) {
14675                return true;
14676              }
14677            }
14678            return false;
14679          }
14680          text = (''+text).toLowerCase();
14681          return (''+obj).toLowerCase().indexOf(text) > -1;
14682        };
14683      }
14684    }
14685
14686    var search = function(obj, text){
14687      if (typeof text == 'string' && text.charAt(0) === '!') {
14688        return !search(obj, text.substr(1));
14689      }
14690      switch (typeof obj) {
14691        case "boolean":
14692        case "number":
14693        case "string":
14694          return comparator(obj, text);
14695        case "object":
14696          switch (typeof text) {
14697            case "object":
14698              return comparator(obj, text);
14699            default:
14700              for ( var objKey in obj) {
14701                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14702                  return true;
14703                }
14704              }
14705              break;
14706          }
14707          return false;
14708        case "array":
14709          for ( var i = 0; i < obj.length; i++) {
14710            if (search(obj[i], text)) {
14711              return true;
14712            }
14713          }
14714          return false;
14715        default:
14716          return false;
14717      }
14718    };
14719    switch (typeof expression) {
14720      case "boolean":
14721      case "number":
14722      case "string":
14723        // Set up expression object and fall through
14724        expression = {$:expression};
14725        // jshint -W086
14726      case "object":
14727        // jshint +W086
14728        for (var key in expression) {
14729          (function(path) {
14730            if (typeof expression[path] === 'undefined') return;
14731            predicates.push(function(value) {
14732              return search(path == '$' ? value : (value && value[path]), expression[path]);
14733            });
14734          })(key);
14735        }
14736        break;
14737      case 'function':
14738        predicates.push(expression);
14739        break;
14740      default:
14741        return array;
14742    }
14743    var filtered = [];
14744    for ( var j = 0; j < array.length; j++) {
14745      var value = array[j];
14746      if (predicates.check(value)) {
14747        filtered.push(value);
14748      }
14749    }
14750    return filtered;
14751  };
14752}
14753
14754/**
14755 * @ngdoc filter
14756 * @name currency
14757 * @kind function
14758 *
14759 * @description
14760 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14761 * symbol for current locale is used.
14762 *
14763 * @param {number} amount Input to filter.
14764 * @param {string=} symbol Currency symbol or identifier to be displayed.
14765 * @returns {string} Formatted number.
14766 *
14767 *
14768 * @example
14769   <example>
14770     <file name="index.html">
14771       <script>
14772         function Ctrl($scope) {
14773           $scope.amount = 1234.56;
14774         }
14775       </script>
14776       <div ng-controller="Ctrl">
14777         <input type="number" ng-model="amount"> <br>
14778         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14779         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14780       </div>
14781     </file>
14782     <file name="protractor.js" type="protractor">
14783       it('should init with 1234.56', function() {
14784         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14785         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14786       });
14787       it('should update', function() {
14788         if (browser.params.browser == 'safari') {
14789           // Safari does not understand the minus key. See
14790           // https://github.com/angular/protractor/issues/481
14791           return;
14792         }
14793         element(by.model('amount')).clear();
14794         element(by.model('amount')).sendKeys('-1234');
14795         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14796         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14797       });
14798     </file>
14799   </example>
14800 */
14801currencyFilter.$inject = ['$locale'];
14802function currencyFilter($locale) {
14803  var formats = $locale.NUMBER_FORMATS;
14804  return function(amount, currencySymbol){
14805    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14806    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14807                replace(/\u00A4/g, currencySymbol);
14808  };
14809}
14810
14811/**
14812 * @ngdoc filter
14813 * @name number
14814 * @kind function
14815 *
14816 * @description
14817 * Formats a number as text.
14818 *
14819 * If the input is not a number an empty string is returned.
14820 *
14821 * @param {number|string} number Number to format.
14822 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14823 * If this is not provided then the fraction size is computed from the current locale's number
14824 * formatting pattern. In the case of the default locale, it will be 3.
14825 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14826 *
14827 * @example
14828   <example>
14829     <file name="index.html">
14830       <script>
14831         function Ctrl($scope) {
14832           $scope.val = 1234.56789;
14833         }
14834       </script>
14835       <div ng-controller="Ctrl">
14836         Enter number: <input ng-model='val'><br>
14837         Default formatting: <span id='number-default'>{{val | number}}</span><br>
14838         No fractions: <span>{{val | number:0}}</span><br>
14839         Negative number: <span>{{-val | number:4}}</span>
14840       </div>
14841     </file>
14842     <file name="protractor.js" type="protractor">
14843       it('should format numbers', function() {
14844         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14845         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14846         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14847       });
14848
14849       it('should update', function() {
14850         element(by.model('val')).clear();
14851         element(by.model('val')).sendKeys('3374.333');
14852         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14853         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14854         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14855      });
14856     </file>
14857   </example>
14858 */
14859
14860
14861numberFilter.$inject = ['$locale'];
14862function numberFilter($locale) {
14863  var formats = $locale.NUMBER_FORMATS;
14864  return function(number, fractionSize) {
14865    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14866      fractionSize);
14867  };
14868}
14869
14870var DECIMAL_SEP = '.';
14871function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14872  if (number == null || !isFinite(number) || isObject(number)) return '';
14873
14874  var isNegative = number < 0;
14875  number = Math.abs(number);
14876  var numStr = number + '',
14877      formatedText = '',
14878      parts = [];
14879
14880  var hasExponent = false;
14881  if (numStr.indexOf('e') !== -1) {
14882    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14883    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14884      numStr = '0';
14885      number = 0;
14886    } else {
14887      formatedText = numStr;
14888      hasExponent = true;
14889    }
14890  }
14891
14892  if (!hasExponent) {
14893    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14894
14895    // determine fractionSize if it is not specified
14896    if (isUndefined(fractionSize)) {
14897      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14898    }
14899
14900    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
14901    // inspired by:
14902    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
14903    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
14904
14905    var fraction = ('' + number).split(DECIMAL_SEP);
14906    var whole = fraction[0];
14907    fraction = fraction[1] || '';
14908
14909    var i, pos = 0,
14910        lgroup = pattern.lgSize,
14911        group = pattern.gSize;
14912
14913    if (whole.length >= (lgroup + group)) {
14914      pos = whole.length - lgroup;
14915      for (i = 0; i < pos; i++) {
14916        if ((pos - i)%group === 0 && i !== 0) {
14917          formatedText += groupSep;
14918        }
14919        formatedText += whole.charAt(i);
14920      }
14921    }
14922
14923    for (i = pos; i < whole.length; i++) {
14924      if ((whole.length - i)%lgroup === 0 && i !== 0) {
14925        formatedText += groupSep;
14926      }
14927      formatedText += whole.charAt(i);
14928    }
14929
14930    // format fraction part.
14931    while(fraction.length < fractionSize) {
14932      fraction += '0';
14933    }
14934
14935    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
14936  } else {
14937
14938    if (fractionSize > 0 && number > -1 && number < 1) {
14939      formatedText = number.toFixed(fractionSize);
14940    }
14941  }
14942
14943  parts.push(isNegative ? pattern.negPre : pattern.posPre);
14944  parts.push(formatedText);
14945  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
14946  return parts.join('');
14947}
14948
14949function padNumber(num, digits, trim) {
14950  var neg = '';
14951  if (num < 0) {
14952    neg =  '-';
14953    num = -num;
14954  }
14955  num = '' + num;
14956  while(num.length < digits) num = '0' + num;
14957  if (trim)
14958    num = num.substr(num.length - digits);
14959  return neg + num;
14960}
14961
14962
14963function dateGetter(name, size, offset, trim) {
14964  offset = offset || 0;
14965  return function(date) {
14966    var value = date['get' + name]();
14967    if (offset > 0 || value > -offset)
14968      value += offset;
14969    if (value === 0 && offset == -12 ) value = 12;
14970    return padNumber(value, size, trim);
14971  };
14972}
14973
14974function dateStrGetter(name, shortForm) {
14975  return function(date, formats) {
14976    var value = date['get' + name]();
14977    var get = uppercase(shortForm ? ('SHORT' + name) : name);
14978
14979    return formats[get][value];
14980  };
14981}
14982
14983function timeZoneGetter(date) {
14984  var zone = -1 * date.getTimezoneOffset();
14985  var paddedZone = (zone >= 0) ? "+" : "";
14986
14987  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
14988                padNumber(Math.abs(zone % 60), 2);
14989
14990  return paddedZone;
14991}
14992
14993function ampmGetter(date, formats) {
14994  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
14995}
14996
14997var DATE_FORMATS = {
14998  yyyy: dateGetter('FullYear', 4),
14999    yy: dateGetter('FullYear', 2, 0, true),
15000     y: dateGetter('FullYear', 1),
15001  MMMM: dateStrGetter('Month'),
15002   MMM: dateStrGetter('Month', true),
15003    MM: dateGetter('Month', 2, 1),
15004     M: dateGetter('Month', 1, 1),
15005    dd: dateGetter('Date', 2),
15006     d: dateGetter('Date', 1),
15007    HH: dateGetter('Hours', 2),
15008     H: dateGetter('Hours', 1),
15009    hh: dateGetter('Hours', 2, -12),
15010     h: dateGetter('Hours', 1, -12),
15011    mm: dateGetter('Minutes', 2),
15012     m: dateGetter('Minutes', 1),
15013    ss: dateGetter('Seconds', 2),
15014     s: dateGetter('Seconds', 1),
15015     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
15016     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
15017   sss: dateGetter('Milliseconds', 3),
15018  EEEE: dateStrGetter('Day'),
15019   EEE: dateStrGetter('Day', true),
15020     a: ampmGetter,
15021     Z: timeZoneGetter
15022};
15023
15024var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
15025    NUMBER_STRING = /^\-?\d+$/;
15026
15027/**
15028 * @ngdoc filter
15029 * @name date
15030 * @kind function
15031 *
15032 * @description
15033 *   Formats `date` to a string based on the requested `format`.
15034 *
15035 *   `format` string can be composed of the following elements:
15036 *
15037 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
15038 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
15039 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
15040 *   * `'MMMM'`: Month in year (January-December)
15041 *   * `'MMM'`: Month in year (Jan-Dec)
15042 *   * `'MM'`: Month in year, padded (01-12)
15043 *   * `'M'`: Month in year (1-12)
15044 *   * `'dd'`: Day in month, padded (01-31)
15045 *   * `'d'`: Day in month (1-31)
15046 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
15047 *   * `'EEE'`: Day in Week, (Sun-Sat)
15048 *   * `'HH'`: Hour in day, padded (00-23)
15049 *   * `'H'`: Hour in day (0-23)
15050 *   * `'hh'`: Hour in am/pm, padded (01-12)
15051 *   * `'h'`: Hour in am/pm, (1-12)
15052 *   * `'mm'`: Minute in hour, padded (00-59)
15053 *   * `'m'`: Minute in hour (0-59)
15054 *   * `'ss'`: Second in minute, padded (00-59)
15055 *   * `'s'`: Second in minute (0-59)
15056 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
15057 *   * `'a'`: am/pm marker
15058 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
15059 *
15060 *   `format` string can also be one of the following predefined
15061 *   {@link guide/i18n localizable formats}:
15062 *
15063 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
15064 *     (e.g. Sep 3, 2010 12:05:08 pm)
15065 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
15066 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
15067 *     (e.g. Friday, September 3, 2010)
15068 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
15069 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
15070 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
15071 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
15072 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
15073 *
15074 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
15075 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
15076 *   (e.g. `"h 'o''clock'"`).
15077 *
15078 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
15079 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
15080 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
15081 *    specified in the string input, the time is considered to be in the local timezone.
15082 * @param {string=} format Formatting rules (see Description). If not specified,
15083 *    `mediumDate` is used.
15084 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
15085 *
15086 * @example
15087   <example>
15088     <file name="index.html">
15089       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
15090           <span>{{1288323623006 | date:'medium'}}</span><br>
15091       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
15092          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15093       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15094          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15095     </file>
15096     <file name="protractor.js" type="protractor">
15097       it('should format date', function() {
15098         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
15099            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
15100         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
15101            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15102         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15103            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15104       });
15105     </file>
15106   </example>
15107 */
15108dateFilter.$inject = ['$locale'];
15109function dateFilter($locale) {
15110
15111
15112  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
15113                     // 1        2       3         4          5          6          7          8  9     10      11
15114  function jsonStringToDate(string) {
15115    var match;
15116    if (match = string.match(R_ISO8601_STR)) {
15117      var date = new Date(0),
15118          tzHour = 0,
15119          tzMin  = 0,
15120          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
15121          timeSetter = match[8] ? date.setUTCHours : date.setHours;
15122
15123      if (match[9]) {
15124        tzHour = int(match[9] + match[10]);
15125        tzMin = int(match[9] + match[11]);
15126      }
15127      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
15128      var h = int(match[4]||0) - tzHour;
15129      var m = int(match[5]||0) - tzMin;
15130      var s = int(match[6]||0);
15131      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
15132      timeSetter.call(date, h, m, s, ms);
15133      return date;
15134    }
15135    return string;
15136  }
15137
15138
15139  return function(date, format) {
15140    var text = '',
15141        parts = [],
15142        fn, match;
15143
15144    format = format || 'mediumDate';
15145    format = $locale.DATETIME_FORMATS[format] || format;
15146    if (isString(date)) {
15147      if (NUMBER_STRING.test(date)) {
15148        date = int(date);
15149      } else {
15150        date = jsonStringToDate(date);
15151      }
15152    }
15153
15154    if (isNumber(date)) {
15155      date = new Date(date);
15156    }
15157
15158    if (!isDate(date)) {
15159      return date;
15160    }
15161
15162    while(format) {
15163      match = DATE_FORMATS_SPLIT.exec(format);
15164      if (match) {
15165        parts = concat(parts, match, 1);
15166        format = parts.pop();
15167      } else {
15168        parts.push(format);
15169        format = null;
15170      }
15171    }
15172
15173    forEach(parts, function(value){
15174      fn = DATE_FORMATS[value];
15175      text += fn ? fn(date, $locale.DATETIME_FORMATS)
15176                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
15177    });
15178
15179    return text;
15180  };
15181}
15182
15183
15184/**
15185 * @ngdoc filter
15186 * @name json
15187 * @kind function
15188 *
15189 * @description
15190 *   Allows you to convert a JavaScript object into JSON string.
15191 *
15192 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
15193 *   the binding is automatically converted to JSON.
15194 *
15195 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
15196 * @returns {string} JSON string.
15197 *
15198 *
15199 * @example
15200   <example>
15201     <file name="index.html">
15202       <pre>{{ {'name':'value'} | json }}</pre>
15203     </file>
15204     <file name="protractor.js" type="protractor">
15205       it('should jsonify filtered objects', function() {
15206         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15207       });
15208     </file>
15209   </example>
15210 *
15211 */
15212function jsonFilter() {
15213  return function(object) {
15214    return toJson(object, true);
15215  };
15216}
15217
15218
15219/**
15220 * @ngdoc filter
15221 * @name lowercase
15222 * @kind function
15223 * @description
15224 * Converts string to lowercase.
15225 * @see angular.lowercase
15226 */
15227var lowercaseFilter = valueFn(lowercase);
15228
15229
15230/**
15231 * @ngdoc filter
15232 * @name uppercase
15233 * @kind function
15234 * @description
15235 * Converts string to uppercase.
15236 * @see angular.uppercase
15237 */
15238var uppercaseFilter = valueFn(uppercase);
15239
15240/**
15241 * @ngdoc filter
15242 * @name limitTo
15243 * @kind function
15244 *
15245 * @description
15246 * Creates a new array or string containing only a specified number of elements. The elements
15247 * are taken from either the beginning or the end of the source array or string, as specified by
15248 * the value and sign (positive or negative) of `limit`.
15249 *
15250 * @param {Array|string} input Source array or string to be limited.
15251 * @param {string|number} limit The length of the returned array or string. If the `limit` number
15252 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15253 *     If the number is negative, `limit` number  of items from the end of the source array/string
15254 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15255 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15256 *     had less than `limit` elements.
15257 *
15258 * @example
15259   <example>
15260     <file name="index.html">
15261       <script>
15262         function Ctrl($scope) {
15263           $scope.numbers = [1,2,3,4,5,6,7,8,9];
15264           $scope.letters = "abcdefghi";
15265           $scope.numLimit = 3;
15266           $scope.letterLimit = 3;
15267         }
15268       </script>
15269       <div ng-controller="Ctrl">
15270         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
15271         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15272         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
15273         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15274       </div>
15275     </file>
15276     <file name="protractor.js" type="protractor">
15277       var numLimitInput = element(by.model('numLimit'));
15278       var letterLimitInput = element(by.model('letterLimit'));
15279       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15280       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15281
15282       it('should limit the number array to first three items', function() {
15283         expect(numLimitInput.getAttribute('value')).toBe('3');
15284         expect(letterLimitInput.getAttribute('value')).toBe('3');
15285         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15286         expect(limitedLetters.getText()).toEqual('Output letters: abc');
15287       });
15288
15289       it('should update the output when -3 is entered', function() {
15290         numLimitInput.clear();
15291         numLimitInput.sendKeys('-3');
15292         letterLimitInput.clear();
15293         letterLimitInput.sendKeys('-3');
15294         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15295         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15296       });
15297
15298       it('should not exceed the maximum size of input array', function() {
15299         numLimitInput.clear();
15300         numLimitInput.sendKeys('100');
15301         letterLimitInput.clear();
15302         letterLimitInput.sendKeys('100');
15303         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15304         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15305       });
15306     </file>
15307   </example>
15308 */
15309function limitToFilter(){
15310  return function(input, limit) {
15311    if (!isArray(input) && !isString(input)) return input;
15312
15313    if (Math.abs(Number(limit)) === Infinity) {
15314      limit = Number(limit);
15315    } else {
15316      limit = int(limit);
15317    }
15318
15319    if (isString(input)) {
15320      //NaN check on limit
15321      if (limit) {
15322        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
15323      } else {
15324        return "";
15325      }
15326    }
15327
15328    var out = [],
15329      i, n;
15330
15331    // if abs(limit) exceeds maximum length, trim it
15332    if (limit > input.length)
15333      limit = input.length;
15334    else if (limit < -input.length)
15335      limit = -input.length;
15336
15337    if (limit > 0) {
15338      i = 0;
15339      n = limit;
15340    } else {
15341      i = input.length + limit;
15342      n = input.length;
15343    }
15344
15345    for (; i<n; i++) {
15346      out.push(input[i]);
15347    }
15348
15349    return out;
15350  };
15351}
15352
15353/**
15354 * @ngdoc filter
15355 * @name orderBy
15356 * @kind function
15357 *
15358 * @description
15359 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
15360 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
15361 * correctly, make sure they are actually being saved as numbers and not strings.
15362 *
15363 * @param {Array} array The array to sort.
15364 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
15365 *    used by the comparator to determine the order of elements.
15366 *
15367 *    Can be one of:
15368 *
15369 *    - `function`: Getter function. The result of this function will be sorted using the
15370 *      `<`, `=`, `>` operator.
15371 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
15372 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
15373 *      ascending or descending sort order (for example, +name or -name).
15374 *    - `Array`: An array of function or string predicates. The first predicate in the array
15375 *      is used for sorting, but when two items are equivalent, the next predicate is used.
15376 *
15377 * @param {boolean=} reverse Reverse the order of the array.
15378 * @returns {Array} Sorted copy of the source array.
15379 *
15380 * @example
15381   <example>
15382     <file name="index.html">
15383       <script>
15384         function Ctrl($scope) {
15385           $scope.friends =
15386               [{name:'John', phone:'555-1212', age:10},
15387                {name:'Mary', phone:'555-9876', age:19},
15388                {name:'Mike', phone:'555-4321', age:21},
15389                {name:'Adam', phone:'555-5678', age:35},
15390                {name:'Julie', phone:'555-8765', age:29}]
15391           $scope.predicate = '-age';
15392         }
15393       </script>
15394       <div ng-controller="Ctrl">
15395         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15396         <hr/>
15397         [ <a href="" ng-click="predicate=''">unsorted</a> ]
15398         <table class="friend">
15399           <tr>
15400             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15401                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15402             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15403             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15404           </tr>
15405           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15406             <td>{{friend.name}}</td>
15407             <td>{{friend.phone}}</td>
15408             <td>{{friend.age}}</td>
15409           </tr>
15410         </table>
15411       </div>
15412     </file>
15413   </example>
15414 *
15415 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
15416 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
15417 * desired parameters.
15418 *
15419 * Example:
15420 *
15421 * @example
15422  <example>
15423    <file name="index.html">
15424      <div ng-controller="Ctrl">
15425        <table class="friend">
15426          <tr>
15427            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
15428              (<a href="" ng-click="order('-name',false)">^</a>)</th>
15429            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
15430            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
15431          </tr>
15432          <tr ng-repeat="friend in friends">
15433            <td>{{friend.name}}</td>
15434            <td>{{friend.phone}}</td>
15435            <td>{{friend.age}}</td>
15436          </tr>
15437        </table>
15438      </div>
15439    </file>
15440
15441    <file name="script.js">
15442      function Ctrl($scope, $filter) {
15443        var orderBy = $filter('orderBy');
15444        $scope.friends = [
15445          { name: 'John',    phone: '555-1212',    age: 10 },
15446          { name: 'Mary',    phone: '555-9876',    age: 19 },
15447          { name: 'Mike',    phone: '555-4321',    age: 21 },
15448          { name: 'Adam',    phone: '555-5678',    age: 35 },
15449          { name: 'Julie',   phone: '555-8765',    age: 29 }
15450        ];
15451
15452        $scope.order = function(predicate, reverse) {
15453          $scope.friends = orderBy($scope.friends, predicate, reverse);
15454        };
15455        $scope.order('-age',false);
15456      }
15457    </file>
15458</example>
15459 */
15460orderByFilter.$inject = ['$parse'];
15461function orderByFilter($parse){
15462  return function(array, sortPredicate, reverseOrder) {
15463    if (!isArray(array)) return array;
15464    if (!sortPredicate) return array;
15465    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15466    sortPredicate = map(sortPredicate, function(predicate){
15467      var descending = false, get = predicate || identity;
15468      if (isString(predicate)) {
15469        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15470          descending = predicate.charAt(0) == '-';
15471          predicate = predicate.substring(1);
15472        }
15473        get = $parse(predicate);
15474        if (get.constant) {
15475          var key = get();
15476          return reverseComparator(function(a,b) {
15477            return compare(a[key], b[key]);
15478          }, descending);
15479        }
15480      }
15481      return reverseComparator(function(a,b){
15482        return compare(get(a),get(b));
15483      }, descending);
15484    });
15485    var arrayCopy = [];
15486    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
15487    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
15488
15489    function comparator(o1, o2){
15490      for ( var i = 0; i < sortPredicate.length; i++) {
15491        var comp = sortPredicate[i](o1, o2);
15492        if (comp !== 0) return comp;
15493      }
15494      return 0;
15495    }
15496    function reverseComparator(comp, descending) {
15497      return toBoolean(descending)
15498          ? function(a,b){return comp(b,a);}
15499          : comp;
15500    }
15501    function compare(v1, v2){
15502      var t1 = typeof v1;
15503      var t2 = typeof v2;
15504      if (t1 == t2) {
15505        if (t1 == "string") {
15506           v1 = v1.toLowerCase();
15507           v2 = v2.toLowerCase();
15508        }
15509        if (v1 === v2) return 0;
15510        return v1 < v2 ? -1 : 1;
15511      } else {
15512        return t1 < t2 ? -1 : 1;
15513      }
15514    }
15515  };
15516}
15517
15518function ngDirective(directive) {
15519  if (isFunction(directive)) {
15520    directive = {
15521      link: directive
15522    };
15523  }
15524  directive.restrict = directive.restrict || 'AC';
15525  return valueFn(directive);
15526}
15527
15528/**
15529 * @ngdoc directive
15530 * @name a
15531 * @restrict E
15532 *
15533 * @description
15534 * Modifies the default behavior of the html A tag so that the default action is prevented when
15535 * the href attribute is empty.
15536 *
15537 * This change permits the easy creation of action links with the `ngClick` directive
15538 * without changing the location or causing page reloads, e.g.:
15539 * `<a href="" ng-click="list.addItem()">Add Item</a>`
15540 */
15541var htmlAnchorDirective = valueFn({
15542  restrict: 'E',
15543  compile: function(element, attr) {
15544
15545    if (msie <= 8) {
15546
15547      // turn <a href ng-click="..">link</a> into a stylable link in IE
15548      // but only if it doesn't have name attribute, in which case it's an anchor
15549      if (!attr.href && !attr.name) {
15550        attr.$set('href', '');
15551      }
15552
15553      // add a comment node to anchors to workaround IE bug that causes element content to be reset
15554      // to new attribute content if attribute is updated with value containing @ and element also
15555      // contains value with @
15556      // see issue #1949
15557      element.append(document.createComment('IE fix'));
15558    }
15559
15560    if (!attr.href && !attr.xlinkHref && !attr.name) {
15561      return function(scope, element) {
15562        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15563        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15564                   'xlink:href' : 'href';
15565        element.on('click', function(event){
15566          // if we have no href url, then don't navigate anywhere.
15567          if (!element.attr(href)) {
15568            event.preventDefault();
15569          }
15570        });
15571      };
15572    }
15573  }
15574});
15575
15576/**
15577 * @ngdoc directive
15578 * @name ngHref
15579 * @restrict A
15580 * @priority 99
15581 *
15582 * @description
15583 * Using Angular markup like `{{hash}}` in an href attribute will
15584 * make the link go to the wrong URL if the user clicks it before
15585 * Angular has a chance to replace the `{{hash}}` markup with its
15586 * value. Until Angular replaces the markup the link will be broken
15587 * and will most likely return a 404 error.
15588 *
15589 * The `ngHref` directive solves this problem.
15590 *
15591 * The wrong way to write it:
15592 * ```html
15593 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15594 * ```
15595 *
15596 * The correct way to write it:
15597 * ```html
15598 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15599 * ```
15600 *
15601 * @element A
15602 * @param {template} ngHref any string which can contain `{{}}` markup.
15603 *
15604 * @example
15605 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15606 * in links and their different behaviors:
15607    <example>
15608      <file name="index.html">
15609        <input ng-model="value" /><br />
15610        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15611        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15612        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15613        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15614        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15615        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15616      </file>
15617      <file name="protractor.js" type="protractor">
15618        it('should execute ng-click but not reload when href without value', function() {
15619          element(by.id('link-1')).click();
15620          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15621          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15622        });
15623
15624        it('should execute ng-click but not reload when href empty string', function() {
15625          element(by.id('link-2')).click();
15626          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15627          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15628        });
15629
15630        it('should execute ng-click and change url when ng-href specified', function() {
15631          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15632
15633          element(by.id('link-3')).click();
15634
15635          // At this point, we navigate away from an Angular page, so we need
15636          // to use browser.driver to get the base webdriver.
15637
15638          browser.wait(function() {
15639            return browser.driver.getCurrentUrl().then(function(url) {
15640              return url.match(/\/123$/);
15641            });
15642          }, 1000, 'page should navigate to /123');
15643        });
15644
15645        xit('should execute ng-click but not reload when href empty string and name specified', function() {
15646          element(by.id('link-4')).click();
15647          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15648          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15649        });
15650
15651        it('should execute ng-click but not reload when no href but name specified', function() {
15652          element(by.id('link-5')).click();
15653          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15654          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15655        });
15656
15657        it('should only change url when only ng-href', function() {
15658          element(by.model('value')).clear();
15659          element(by.model('value')).sendKeys('6');
15660          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15661
15662          element(by.id('link-6')).click();
15663
15664          // At this point, we navigate away from an Angular page, so we need
15665          // to use browser.driver to get the base webdriver.
15666          browser.wait(function() {
15667            return browser.driver.getCurrentUrl().then(function(url) {
15668              return url.match(/\/6$/);
15669            });
15670          }, 1000, 'page should navigate to /6');
15671        });
15672      </file>
15673    </example>
15674 */
15675
15676/**
15677 * @ngdoc directive
15678 * @name ngSrc
15679 * @restrict A
15680 * @priority 99
15681 *
15682 * @description
15683 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15684 * work right: The browser will fetch from the URL with the literal
15685 * text `{{hash}}` until Angular replaces the expression inside
15686 * `{{hash}}`. The `ngSrc` directive solves this problem.
15687 *
15688 * The buggy way to write it:
15689 * ```html
15690 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15691 * ```
15692 *
15693 * The correct way to write it:
15694 * ```html
15695 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15696 * ```
15697 *
15698 * @element IMG
15699 * @param {template} ngSrc any string which can contain `{{}}` markup.
15700 */
15701
15702/**
15703 * @ngdoc directive
15704 * @name ngSrcset
15705 * @restrict A
15706 * @priority 99
15707 *
15708 * @description
15709 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15710 * work right: The browser will fetch from the URL with the literal
15711 * text `{{hash}}` until Angular replaces the expression inside
15712 * `{{hash}}`. The `ngSrcset` directive solves this problem.
15713 *
15714 * The buggy way to write it:
15715 * ```html
15716 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15717 * ```
15718 *
15719 * The correct way to write it:
15720 * ```html
15721 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15722 * ```
15723 *
15724 * @element IMG
15725 * @param {template} ngSrcset any string which can contain `{{}}` markup.
15726 */
15727
15728/**
15729 * @ngdoc directive
15730 * @name ngDisabled
15731 * @restrict A
15732 * @priority 100
15733 *
15734 * @description
15735 *
15736 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15737 * ```html
15738 * <div ng-init="scope = { isDisabled: false }">
15739 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15740 * </div>
15741 * ```
15742 *
15743 * The HTML specification does not require browsers to preserve the values of boolean attributes
15744 * such as disabled. (Their presence means true and their absence means false.)
15745 * If we put an Angular interpolation expression into such an attribute then the
15746 * binding information would be lost when the browser removes the attribute.
15747 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15748 * This complementary directive is not removed by the browser and so provides
15749 * a permanent reliable place to store the binding information.
15750 *
15751 * @example
15752    <example>
15753      <file name="index.html">
15754        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15755        <button ng-model="button" ng-disabled="checked">Button</button>
15756      </file>
15757      <file name="protractor.js" type="protractor">
15758        it('should toggle button', function() {
15759          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
15760          element(by.model('checked')).click();
15761          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
15762        });
15763      </file>
15764    </example>
15765 *
15766 * @element INPUT
15767 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
15768 *     then special attribute "disabled" will be set on the element
15769 */
15770
15771
15772/**
15773 * @ngdoc directive
15774 * @name ngChecked
15775 * @restrict A
15776 * @priority 100
15777 *
15778 * @description
15779 * The HTML specification does not require browsers to preserve the values of boolean attributes
15780 * such as checked. (Their presence means true and their absence means false.)
15781 * If we put an Angular interpolation expression into such an attribute then the
15782 * binding information would be lost when the browser removes the attribute.
15783 * The `ngChecked` directive solves this problem for the `checked` attribute.
15784 * This complementary directive is not removed by the browser and so provides
15785 * a permanent reliable place to store the binding information.
15786 * @example
15787    <example>
15788      <file name="index.html">
15789        Check me to check both: <input type="checkbox" ng-model="master"><br/>
15790        <input id="checkSlave" type="checkbox" ng-checked="master">
15791      </file>
15792      <file name="protractor.js" type="protractor">
15793        it('should check both checkBoxes', function() {
15794          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15795          element(by.model('master')).click();
15796          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15797        });
15798      </file>
15799    </example>
15800 *
15801 * @element INPUT
15802 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
15803 *     then special attribute "checked" will be set on the element
15804 */
15805
15806
15807/**
15808 * @ngdoc directive
15809 * @name ngReadonly
15810 * @restrict A
15811 * @priority 100
15812 *
15813 * @description
15814 * The HTML specification does not require browsers to preserve the values of boolean attributes
15815 * such as readonly. (Their presence means true and their absence means false.)
15816 * If we put an Angular interpolation expression into such an attribute then the
15817 * binding information would be lost when the browser removes the attribute.
15818 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15819 * This complementary directive is not removed by the browser and so provides
15820 * a permanent reliable place to store the binding information.
15821 * @example
15822    <example>
15823      <file name="index.html">
15824        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15825        <input type="text" ng-readonly="checked" value="I'm Angular"/>
15826      </file>
15827      <file name="protractor.js" type="protractor">
15828        it('should toggle readonly attr', function() {
15829          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
15830          element(by.model('checked')).click();
15831          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
15832        });
15833      </file>
15834    </example>
15835 *
15836 * @element INPUT
15837 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
15838 *     then special attribute "readonly" will be set on the element
15839 */
15840
15841
15842/**
15843 * @ngdoc directive
15844 * @name ngSelected
15845 * @restrict A
15846 * @priority 100
15847 *
15848 * @description
15849 * The HTML specification does not require browsers to preserve the values of boolean attributes
15850 * such as selected. (Their presence means true and their absence means false.)
15851 * If we put an Angular interpolation expression into such an attribute then the
15852 * binding information would be lost when the browser removes the attribute.
15853 * The `ngSelected` directive solves this problem for the `selected` attribute.
15854 * This complementary directive is not removed by the browser and so provides
15855 * a permanent reliable place to store the binding information.
15856 *
15857 * @example
15858    <example>
15859      <file name="index.html">
15860        Check me to select: <input type="checkbox" ng-model="selected"><br/>
15861        <select>
15862          <option>Hello!</option>
15863          <option id="greet" ng-selected="selected">Greetings!</option>
15864        </select>
15865      </file>
15866      <file name="protractor.js" type="protractor">
15867        it('should select Greetings!', function() {
15868          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15869          element(by.model('selected')).click();
15870          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15871        });
15872      </file>
15873    </example>
15874 *
15875 * @element OPTION
15876 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
15877 *     then special attribute "selected" will be set on the element
15878 */
15879
15880/**
15881 * @ngdoc directive
15882 * @name ngOpen
15883 * @restrict A
15884 * @priority 100
15885 *
15886 * @description
15887 * The HTML specification does not require browsers to preserve the values of boolean attributes
15888 * such as open. (Their presence means true and their absence means false.)
15889 * If we put an Angular interpolation expression into such an attribute then the
15890 * binding information would be lost when the browser removes the attribute.
15891 * The `ngOpen` directive solves this problem for the `open` attribute.
15892 * This complementary directive is not removed by the browser and so provides
15893 * a permanent reliable place to store the binding information.
15894 * @example
15895     <example>
15896       <file name="index.html">
15897         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15898         <details id="details" ng-open="open">
15899            <summary>Show/Hide me</summary>
15900         </details>
15901       </file>
15902       <file name="protractor.js" type="protractor">
15903         it('should toggle open', function() {
15904           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15905           element(by.model('open')).click();
15906           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15907         });
15908       </file>
15909     </example>
15910 *
15911 * @element DETAILS
15912 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
15913 *     then special attribute "open" will be set on the element
15914 */
15915
15916var ngAttributeAliasDirectives = {};
15917
15918
15919// boolean attrs are evaluated
15920forEach(BOOLEAN_ATTR, function(propName, attrName) {
15921  // binding to multiple is not supported
15922  if (propName == "multiple") return;
15923
15924  var normalized = directiveNormalize('ng-' + attrName);
15925  ngAttributeAliasDirectives[normalized] = function() {
15926    return {
15927      priority: 100,
15928      link: function(scope, element, attr) {
15929        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
15930          attr.$set(attrName, !!value);
15931        });
15932      }
15933    };
15934  };
15935});
15936
15937
15938// ng-src, ng-srcset, ng-href are interpolated
15939forEach(['src', 'srcset', 'href'], function(attrName) {
15940  var normalized = directiveNormalize('ng-' + attrName);
15941  ngAttributeAliasDirectives[normalized] = function() {
15942    return {
15943      priority: 99, // it needs to run after the attributes are interpolated
15944      link: function(scope, element, attr) {
15945        var propName = attrName,
15946            name = attrName;
15947
15948        if (attrName === 'href' &&
15949            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
15950          name = 'xlinkHref';
15951          attr.$attr[name] = 'xlink:href';
15952          propName = null;
15953        }
15954
15955        attr.$observe(normalized, function(value) {
15956          if (!value)
15957             return;
15958
15959          attr.$set(name, value);
15960
15961          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
15962          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
15963          // to set the property as well to achieve the desired effect.
15964          // we use attr[attrName] value since $set can sanitize the url.
15965          if (msie && propName) element.prop(propName, attr[name]);
15966        });
15967      }
15968    };
15969  };
15970});
15971
15972/* global -nullFormCtrl */
15973var nullFormCtrl = {
15974  $addControl: noop,
15975  $removeControl: noop,
15976  $setValidity: noop,
15977  $setDirty: noop,
15978  $setPristine: noop
15979};
15980
15981/**
15982 * @ngdoc type
15983 * @name form.FormController
15984 *
15985 * @property {boolean} $pristine True if user has not interacted with the form yet.
15986 * @property {boolean} $dirty True if user has already interacted with the form.
15987 * @property {boolean} $valid True if all of the containing forms and controls are valid.
15988 * @property {boolean} $invalid True if at least one containing control or form is invalid.
15989 *
15990 * @property {Object} $error Is an object hash, containing references to all invalid controls or
15991 *  forms, where:
15992 *
15993 *  - keys are validation tokens (error names),
15994 *  - values are arrays of controls or forms that are invalid for given error name.
15995 *
15996 *
15997 *  Built-in validation tokens:
15998 *
15999 *  - `email`
16000 *  - `max`
16001 *  - `maxlength`
16002 *  - `min`
16003 *  - `minlength`
16004 *  - `number`
16005 *  - `pattern`
16006 *  - `required`
16007 *  - `url`
16008 *
16009 * @description
16010 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
16011 * such as being valid/invalid or dirty/pristine.
16012 *
16013 * Each {@link ng.directive:form form} directive creates an instance
16014 * of `FormController`.
16015 *
16016 */
16017//asks for $scope to fool the BC controller module
16018FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
16019function FormController(element, attrs, $scope, $animate) {
16020  var form = this,
16021      parentForm = element.parent().controller('form') || nullFormCtrl,
16022      invalidCount = 0, // used to easily determine if we are valid
16023      errors = form.$error = {},
16024      controls = [];
16025
16026  // init state
16027  form.$name = attrs.name || attrs.ngForm;
16028  form.$dirty = false;
16029  form.$pristine = true;
16030  form.$valid = true;
16031  form.$invalid = false;
16032
16033  parentForm.$addControl(form);
16034
16035  // Setup initial state of the control
16036  element.addClass(PRISTINE_CLASS);
16037  toggleValidCss(true);
16038
16039  // convenience method for easy toggling of classes
16040  function toggleValidCss(isValid, validationErrorKey) {
16041    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16042    $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16043    $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
16044  }
16045
16046  /**
16047   * @ngdoc method
16048   * @name form.FormController#$addControl
16049   *
16050   * @description
16051   * Register a control with the form.
16052   *
16053   * Input elements using ngModelController do this automatically when they are linked.
16054   */
16055  form.$addControl = function(control) {
16056    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
16057    // and not added to the scope.  Now we throw an error.
16058    assertNotHasOwnProperty(control.$name, 'input');
16059    controls.push(control);
16060
16061    if (control.$name) {
16062      form[control.$name] = control;
16063    }
16064  };
16065
16066  /**
16067   * @ngdoc method
16068   * @name form.FormController#$removeControl
16069   *
16070   * @description
16071   * Deregister a control from the form.
16072   *
16073   * Input elements using ngModelController do this automatically when they are destroyed.
16074   */
16075  form.$removeControl = function(control) {
16076    if (control.$name && form[control.$name] === control) {
16077      delete form[control.$name];
16078    }
16079    forEach(errors, function(queue, validationToken) {
16080      form.$setValidity(validationToken, true, control);
16081    });
16082
16083    arrayRemove(controls, control);
16084  };
16085
16086  /**
16087   * @ngdoc method
16088   * @name form.FormController#$setValidity
16089   *
16090   * @description
16091   * Sets the validity of a form control.
16092   *
16093   * This method will also propagate to parent forms.
16094   */
16095  form.$setValidity = function(validationToken, isValid, control) {
16096    var queue = errors[validationToken];
16097
16098    if (isValid) {
16099      if (queue) {
16100        arrayRemove(queue, control);
16101        if (!queue.length) {
16102          invalidCount--;
16103          if (!invalidCount) {
16104            toggleValidCss(isValid);
16105            form.$valid = true;
16106            form.$invalid = false;
16107          }
16108          errors[validationToken] = false;
16109          toggleValidCss(true, validationToken);
16110          parentForm.$setValidity(validationToken, true, form);
16111        }
16112      }
16113
16114    } else {
16115      if (!invalidCount) {
16116        toggleValidCss(isValid);
16117      }
16118      if (queue) {
16119        if (includes(queue, control)) return;
16120      } else {
16121        errors[validationToken] = queue = [];
16122        invalidCount++;
16123        toggleValidCss(false, validationToken);
16124        parentForm.$setValidity(validationToken, false, form);
16125      }
16126      queue.push(control);
16127
16128      form.$valid = false;
16129      form.$invalid = true;
16130    }
16131  };
16132
16133  /**
16134   * @ngdoc method
16135   * @name form.FormController#$setDirty
16136   *
16137   * @description
16138   * Sets the form to a dirty state.
16139   *
16140   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
16141   * state (ng-dirty class). This method will also propagate to parent forms.
16142   */
16143  form.$setDirty = function() {
16144    $animate.removeClass(element, PRISTINE_CLASS);
16145    $animate.addClass(element, DIRTY_CLASS);
16146    form.$dirty = true;
16147    form.$pristine = false;
16148    parentForm.$setDirty();
16149  };
16150
16151  /**
16152   * @ngdoc method
16153   * @name form.FormController#$setPristine
16154   *
16155   * @description
16156   * Sets the form to its pristine state.
16157   *
16158   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
16159   * state (ng-pristine class). This method will also propagate to all the controls contained
16160   * in this form.
16161   *
16162   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
16163   * saving or resetting it.
16164   */
16165  form.$setPristine = function () {
16166    $animate.removeClass(element, DIRTY_CLASS);
16167    $animate.addClass(element, PRISTINE_CLASS);
16168    form.$dirty = false;
16169    form.$pristine = true;
16170    forEach(controls, function(control) {
16171      control.$setPristine();
16172    });
16173  };
16174}
16175
16176
16177/**
16178 * @ngdoc directive
16179 * @name ngForm
16180 * @restrict EAC
16181 *
16182 * @description
16183 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
16184 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
16185 * sub-group of controls needs to be determined.
16186 *
16187 * Note: the purpose of `ngForm` is to group controls,
16188 * but not to be a replacement for the `<form>` tag with all of its capabilities
16189 * (e.g. posting to the server, ...).
16190 *
16191 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
16192 *                       related scope, under this name.
16193 *
16194 */
16195
16196 /**
16197 * @ngdoc directive
16198 * @name form
16199 * @restrict E
16200 *
16201 * @description
16202 * Directive that instantiates
16203 * {@link form.FormController FormController}.
16204 *
16205 * If the `name` attribute is specified, the form controller is published onto the current scope under
16206 * this name.
16207 *
16208 * # Alias: {@link ng.directive:ngForm `ngForm`}
16209 *
16210 * In Angular forms can be nested. This means that the outer form is valid when all of the child
16211 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
16212 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
16213 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
16214 * using Angular validation directives in forms that are dynamically generated using the
16215 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
16216 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
16217 * `ngForm` directive and nest these in an outer `form` element.
16218 *
16219 *
16220 * # CSS classes
16221 *  - `ng-valid` is set if the form is valid.
16222 *  - `ng-invalid` is set if the form is invalid.
16223 *  - `ng-pristine` is set if the form is pristine.
16224 *  - `ng-dirty` is set if the form is dirty.
16225 *
16226 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
16227 *
16228 *
16229 * # Submitting a form and preventing the default action
16230 *
16231 * Since the role of forms in client-side Angular applications is different than in classical
16232 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
16233 * page reload that sends the data to the server. Instead some javascript logic should be triggered
16234 * to handle the form submission in an application-specific way.
16235 *
16236 * For this reason, Angular prevents the default action (form submission to the server) unless the
16237 * `<form>` element has an `action` attribute specified.
16238 *
16239 * You can use one of the following two ways to specify what javascript method should be called when
16240 * a form is submitted:
16241 *
16242 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
16243 * - {@link ng.directive:ngClick ngClick} directive on the first
16244  *  button or input field of type submit (input[type=submit])
16245 *
16246 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
16247 * or {@link ng.directive:ngClick ngClick} directives.
16248 * This is because of the following form submission rules in the HTML specification:
16249 *
16250 * - If a form has only one input field then hitting enter in this field triggers form submit
16251 * (`ngSubmit`)
16252 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
16253 * doesn't trigger submit
16254 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16255 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16256 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16257 *
16258 * @param {string=} name Name of the form. If specified, the form controller will be published into
16259 *                       related scope, under this name.
16260 *
16261 * ## Animation Hooks
16262 *
16263 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16264 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16265 * other validations that are performed within the form. Animations in ngForm are similar to how
16266 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16267 * as JS animations.
16268 *
16269 * The following example shows a simple way to utilize CSS transitions to style a form element
16270 * that has been rendered as invalid after it has been validated:
16271 *
16272 * <pre>
16273 * //be sure to include ngAnimate as a module to hook into more
16274 * //advanced animations
16275 * .my-form {
16276 *   transition:0.5s linear all;
16277 *   background: white;
16278 * }
16279 * .my-form.ng-invalid {
16280 *   background: red;
16281 *   color:white;
16282 * }
16283 * </pre>
16284 *
16285 * @example
16286    <example deps="angular-animate.js" animations="true" fixBase="true">
16287      <file name="index.html">
16288       <script>
16289         function Ctrl($scope) {
16290           $scope.userType = 'guest';
16291         }
16292       </script>
16293       <style>
16294        .my-form {
16295          -webkit-transition:all linear 0.5s;
16296          transition:all linear 0.5s;
16297          background: transparent;
16298        }
16299        .my-form.ng-invalid {
16300          background: red;
16301        }
16302       </style>
16303       <form name="myForm" ng-controller="Ctrl" class="my-form">
16304         userType: <input name="input" ng-model="userType" required>
16305         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16306         <tt>userType = {{userType}}</tt><br>
16307         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16308         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16309         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16310         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16311        </form>
16312      </file>
16313      <file name="protractor.js" type="protractor">
16314        it('should initialize to model', function() {
16315          var userType = element(by.binding('userType'));
16316          var valid = element(by.binding('myForm.input.$valid'));
16317
16318          expect(userType.getText()).toContain('guest');
16319          expect(valid.getText()).toContain('true');
16320        });
16321
16322        it('should be invalid if empty', function() {
16323          var userType = element(by.binding('userType'));
16324          var valid = element(by.binding('myForm.input.$valid'));
16325          var userInput = element(by.model('userType'));
16326
16327          userInput.clear();
16328          userInput.sendKeys('');
16329
16330          expect(userType.getText()).toEqual('userType =');
16331          expect(valid.getText()).toContain('false');
16332        });
16333      </file>
16334    </example>
16335 *
16336 */
16337var formDirectiveFactory = function(isNgForm) {
16338  return ['$timeout', function($timeout) {
16339    var formDirective = {
16340      name: 'form',
16341      restrict: isNgForm ? 'EAC' : 'E',
16342      controller: FormController,
16343      compile: function() {
16344        return {
16345          pre: function(scope, formElement, attr, controller) {
16346            if (!attr.action) {
16347              // we can't use jq events because if a form is destroyed during submission the default
16348              // action is not prevented. see #1238
16349              //
16350              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16351              // page reload if the form was destroyed by submission of the form via a click handler
16352              // on a button in the form. Looks like an IE9 specific bug.
16353              var preventDefaultListener = function(event) {
16354                event.preventDefault
16355                  ? event.preventDefault()
16356                  : event.returnValue = false; // IE
16357              };
16358
16359              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16360
16361              // unregister the preventDefault listener so that we don't not leak memory but in a
16362              // way that will achieve the prevention of the default action.
16363              formElement.on('$destroy', function() {
16364                $timeout(function() {
16365                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16366                }, 0, false);
16367              });
16368            }
16369
16370            var parentFormCtrl = formElement.parent().controller('form'),
16371                alias = attr.name || attr.ngForm;
16372
16373            if (alias) {
16374              setter(scope, alias, controller, alias);
16375            }
16376            if (parentFormCtrl) {
16377              formElement.on('$destroy', function() {
16378                parentFormCtrl.$removeControl(controller);
16379                if (alias) {
16380                  setter(scope, alias, undefined, alias);
16381                }
16382                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16383              });
16384            }
16385          }
16386        };
16387      }
16388    };
16389
16390    return formDirective;
16391  }];
16392};
16393
16394var formDirective = formDirectiveFactory();
16395var ngFormDirective = formDirectiveFactory(true);
16396
16397/* global
16398
16399    -VALID_CLASS,
16400    -INVALID_CLASS,
16401    -PRISTINE_CLASS,
16402    -DIRTY_CLASS
16403*/
16404
16405var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16406var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
16407var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16408
16409var inputType = {
16410
16411  /**
16412   * @ngdoc input
16413   * @name input[text]
16414   *
16415   * @description
16416   * Standard HTML text input with angular data binding.
16417   *
16418   * @param {string} ngModel Assignable angular expression to data-bind to.
16419   * @param {string=} name Property name of the form under which the control is published.
16420   * @param {string=} required Adds `required` validation error key if the value is not entered.
16421   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16422   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16423   *    `required` when you want to data-bind to the `required` attribute.
16424   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16425   *    minlength.
16426   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16427   *    maxlength.
16428   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16429   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16430   *    patterns defined as scope expressions.
16431   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16432   *    interaction with the input element.
16433   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16434   *
16435   * @example
16436      <example name="text-input-directive">
16437        <file name="index.html">
16438         <script>
16439           function Ctrl($scope) {
16440             $scope.text = 'guest';
16441             $scope.word = /^\s*\w*\s*$/;
16442           }
16443         </script>
16444         <form name="myForm" ng-controller="Ctrl">
16445           Single word: <input type="text" name="input" ng-model="text"
16446                               ng-pattern="word" required ng-trim="false">
16447           <span class="error" ng-show="myForm.input.$error.required">
16448             Required!</span>
16449           <span class="error" ng-show="myForm.input.$error.pattern">
16450             Single word only!</span>
16451
16452           <tt>text = {{text}}</tt><br/>
16453           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16454           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16455           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16456           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16457          </form>
16458        </file>
16459        <file name="protractor.js" type="protractor">
16460          var text = element(by.binding('text'));
16461          var valid = element(by.binding('myForm.input.$valid'));
16462          var input = element(by.model('text'));
16463
16464          it('should initialize to model', function() {
16465            expect(text.getText()).toContain('guest');
16466            expect(valid.getText()).toContain('true');
16467          });
16468
16469          it('should be invalid if empty', function() {
16470            input.clear();
16471            input.sendKeys('');
16472
16473            expect(text.getText()).toEqual('text =');
16474            expect(valid.getText()).toContain('false');
16475          });
16476
16477          it('should be invalid if multi word', function() {
16478            input.clear();
16479            input.sendKeys('hello world');
16480
16481            expect(valid.getText()).toContain('false');
16482          });
16483        </file>
16484      </example>
16485   */
16486  'text': textInputType,
16487
16488
16489  /**
16490   * @ngdoc input
16491   * @name input[number]
16492   *
16493   * @description
16494   * Text input with number validation and transformation. Sets the `number` validation
16495   * error if not a valid number.
16496   *
16497   * @param {string} ngModel Assignable angular expression to data-bind to.
16498   * @param {string=} name Property name of the form under which the control is published.
16499   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16500   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16501   * @param {string=} required Sets `required` validation error key if the value is not entered.
16502   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16503   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16504   *    `required` when you want to data-bind to the `required` attribute.
16505   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16506   *    minlength.
16507   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16508   *    maxlength.
16509   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16510   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16511   *    patterns defined as scope expressions.
16512   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16513   *    interaction with the input element.
16514   *
16515   * @example
16516      <example name="number-input-directive">
16517        <file name="index.html">
16518         <script>
16519           function Ctrl($scope) {
16520             $scope.value = 12;
16521           }
16522         </script>
16523         <form name="myForm" ng-controller="Ctrl">
16524           Number: <input type="number" name="input" ng-model="value"
16525                          min="0" max="99" required>
16526           <span class="error" ng-show="myForm.input.$error.required">
16527             Required!</span>
16528           <span class="error" ng-show="myForm.input.$error.number">
16529             Not valid number!</span>
16530           <tt>value = {{value}}</tt><br/>
16531           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16532           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16533           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16534           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16535          </form>
16536        </file>
16537        <file name="protractor.js" type="protractor">
16538          var value = element(by.binding('value'));
16539          var valid = element(by.binding('myForm.input.$valid'));
16540          var input = element(by.model('value'));
16541
16542          it('should initialize to model', function() {
16543            expect(value.getText()).toContain('12');
16544            expect(valid.getText()).toContain('true');
16545          });
16546
16547          it('should be invalid if empty', function() {
16548            input.clear();
16549            input.sendKeys('');
16550            expect(value.getText()).toEqual('value =');
16551            expect(valid.getText()).toContain('false');
16552          });
16553
16554          it('should be invalid if over max', function() {
16555            input.clear();
16556            input.sendKeys('123');
16557            expect(value.getText()).toEqual('value =');
16558            expect(valid.getText()).toContain('false');
16559          });
16560        </file>
16561      </example>
16562   */
16563  'number': numberInputType,
16564
16565
16566  /**
16567   * @ngdoc input
16568   * @name input[url]
16569   *
16570   * @description
16571   * Text input with URL validation. Sets the `url` validation error key if the content is not a
16572   * valid URL.
16573   *
16574   * @param {string} ngModel Assignable angular expression to data-bind to.
16575   * @param {string=} name Property name of the form under which the control is published.
16576   * @param {string=} required Sets `required` validation error key if the value is not entered.
16577   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16578   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16579   *    `required` when you want to data-bind to the `required` attribute.
16580   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16581   *    minlength.
16582   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16583   *    maxlength.
16584   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16585   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16586   *    patterns defined as scope expressions.
16587   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16588   *    interaction with the input element.
16589   *
16590   * @example
16591      <example name="url-input-directive">
16592        <file name="index.html">
16593         <script>
16594           function Ctrl($scope) {
16595             $scope.text = 'http://google.com';
16596           }
16597         </script>
16598         <form name="myForm" ng-controller="Ctrl">
16599           URL: <input type="url" name="input" ng-model="text" required>
16600           <span class="error" ng-show="myForm.input.$error.required">
16601             Required!</span>
16602           <span class="error" ng-show="myForm.input.$error.url">
16603             Not valid url!</span>
16604           <tt>text = {{text}}</tt><br/>
16605           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16606           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16607           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16608           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16609           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16610          </form>
16611        </file>
16612        <file name="protractor.js" type="protractor">
16613          var text = element(by.binding('text'));
16614          var valid = element(by.binding('myForm.input.$valid'));
16615          var input = element(by.model('text'));
16616
16617          it('should initialize to model', function() {
16618            expect(text.getText()).toContain('http://google.com');
16619            expect(valid.getText()).toContain('true');
16620          });
16621
16622          it('should be invalid if empty', function() {
16623            input.clear();
16624            input.sendKeys('');
16625
16626            expect(text.getText()).toEqual('text =');
16627            expect(valid.getText()).toContain('false');
16628          });
16629
16630          it('should be invalid if not url', function() {
16631            input.clear();
16632            input.sendKeys('box');
16633
16634            expect(valid.getText()).toContain('false');
16635          });
16636        </file>
16637      </example>
16638   */
16639  'url': urlInputType,
16640
16641
16642  /**
16643   * @ngdoc input
16644   * @name input[email]
16645   *
16646   * @description
16647   * Text input with email validation. Sets the `email` validation error key if not a valid email
16648   * address.
16649   *
16650   * @param {string} ngModel Assignable angular expression to data-bind to.
16651   * @param {string=} name Property name of the form under which the control is published.
16652   * @param {string=} required Sets `required` validation error key if the value is not entered.
16653   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16654   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16655   *    `required` when you want to data-bind to the `required` attribute.
16656   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16657   *    minlength.
16658   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16659   *    maxlength.
16660   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16661   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16662   *    patterns defined as scope expressions.
16663   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16664   *    interaction with the input element.
16665   *
16666   * @example
16667      <example name="email-input-directive">
16668        <file name="index.html">
16669         <script>
16670           function Ctrl($scope) {
16671             $scope.text = '[email protected]';
16672           }
16673         </script>
16674           <form name="myForm" ng-controller="Ctrl">
16675             Email: <input type="email" name="input" ng-model="text" required>
16676             <span class="error" ng-show="myForm.input.$error.required">
16677               Required!</span>
16678             <span class="error" ng-show="myForm.input.$error.email">
16679               Not valid email!</span>
16680             <tt>text = {{text}}</tt><br/>
16681             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16682             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16683             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16684             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16685             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16686           </form>
16687         </file>
16688        <file name="protractor.js" type="protractor">
16689          var text = element(by.binding('text'));
16690          var valid = element(by.binding('myForm.input.$valid'));
16691          var input = element(by.model('text'));
16692
16693          it('should initialize to model', function() {
16694            expect(text.getText()).toContain('[email protected]');
16695            expect(valid.getText()).toContain('true');
16696          });
16697
16698          it('should be invalid if empty', function() {
16699            input.clear();
16700            input.sendKeys('');
16701            expect(text.getText()).toEqual('text =');
16702            expect(valid.getText()).toContain('false');
16703          });
16704
16705          it('should be invalid if not email', function() {
16706            input.clear();
16707            input.sendKeys('xxx');
16708
16709            expect(valid.getText()).toContain('false');
16710          });
16711        </file>
16712      </example>
16713   */
16714  'email': emailInputType,
16715
16716
16717  /**
16718   * @ngdoc input
16719   * @name input[radio]
16720   *
16721   * @description
16722   * HTML radio button.
16723   *
16724   * @param {string} ngModel Assignable angular expression to data-bind to.
16725   * @param {string} value The value to which the expression should be set when selected.
16726   * @param {string=} name Property name of the form under which the control is published.
16727   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16728   *    interaction with the input element.
16729   * @param {string} ngValue Angular expression which sets the value to which the expression should
16730   *    be set when selected.
16731   *
16732   * @example
16733      <example name="radio-input-directive">
16734        <file name="index.html">
16735         <script>
16736           function Ctrl($scope) {
16737             $scope.color = 'blue';
16738             $scope.specialValue = {
16739               "id": "12345",
16740               "value": "green"
16741             };
16742           }
16743         </script>
16744         <form name="myForm" ng-controller="Ctrl">
16745           <input type="radio" ng-model="color" value="red">  Red <br/>
16746           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16747           <input type="radio" ng-model="color" value="blue"> Blue <br/>
16748           <tt>color = {{color | json}}</tt><br/>
16749          </form>
16750          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16751        </file>
16752        <file name="protractor.js" type="protractor">
16753          it('should change state', function() {
16754            var color = element(by.binding('color'));
16755
16756            expect(color.getText()).toContain('blue');
16757
16758            element.all(by.model('color')).get(0).click();
16759
16760            expect(color.getText()).toContain('red');
16761          });
16762        </file>
16763      </example>
16764   */
16765  'radio': radioInputType,
16766
16767
16768  /**
16769   * @ngdoc input
16770   * @name input[checkbox]
16771   *
16772   * @description
16773   * HTML checkbox.
16774   *
16775   * @param {string} ngModel Assignable angular expression to data-bind to.
16776   * @param {string=} name Property name of the form under which the control is published.
16777   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16778   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16779   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16780   *    interaction with the input element.
16781   *
16782   * @example
16783      <example name="checkbox-input-directive">
16784        <file name="index.html">
16785         <script>
16786           function Ctrl($scope) {
16787             $scope.value1 = true;
16788             $scope.value2 = 'YES'
16789           }
16790         </script>
16791         <form name="myForm" ng-controller="Ctrl">
16792           Value1: <input type="checkbox" ng-model="value1"> <br/>
16793           Value2: <input type="checkbox" ng-model="value2"
16794                          ng-true-value="YES" ng-false-value="NO"> <br/>
16795           <tt>value1 = {{value1}}</tt><br/>
16796           <tt>value2 = {{value2}}</tt><br/>
16797          </form>
16798        </file>
16799        <file name="protractor.js" type="protractor">
16800          it('should change state', function() {
16801            var value1 = element(by.binding('value1'));
16802            var value2 = element(by.binding('value2'));
16803
16804            expect(value1.getText()).toContain('true');
16805            expect(value2.getText()).toContain('YES');
16806
16807            element(by.model('value1')).click();
16808            element(by.model('value2')).click();
16809
16810            expect(value1.getText()).toContain('false');
16811            expect(value2.getText()).toContain('NO');
16812          });
16813        </file>
16814      </example>
16815   */
16816  'checkbox': checkboxInputType,
16817
16818  'hidden': noop,
16819  'button': noop,
16820  'submit': noop,
16821  'reset': noop,
16822  'file': noop
16823};
16824
16825// A helper function to call $setValidity and return the value / undefined,
16826// a pattern that is repeated a lot in the input validation logic.
16827function validate(ctrl, validatorName, validity, value){
16828  ctrl.$setValidity(validatorName, validity);
16829  return validity ? value : undefined;
16830}
16831
16832function testFlags(validity, flags) {
16833  var i, flag;
16834  if (flags) {
16835    for (i=0; i<flags.length; ++i) {
16836      flag = flags[i];
16837      if (validity[flag]) {
16838        return true;
16839      }
16840    }
16841  }
16842  return false;
16843}
16844
16845// Pass validity so that behaviour can be mocked easier.
16846function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
16847  if (isObject(validity)) {
16848    ctrl.$$hasNativeValidators = true;
16849    var validator = function(value) {
16850      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
16851      // perform the required validation)
16852      if (!ctrl.$error[validatorName] &&
16853          !testFlags(validity, ignoreFlags) &&
16854          testFlags(validity, badFlags)) {
16855        ctrl.$setValidity(validatorName, false);
16856        return;
16857      }
16858      return value;
16859    };
16860    ctrl.$parsers.push(validator);
16861  }
16862}
16863
16864function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16865  var validity = element.prop(VALIDITY_STATE_PROPERTY);
16866  var placeholder = element[0].placeholder, noevent = {};
16867  ctrl.$$validityState = validity;
16868
16869  // In composition mode, users are still inputing intermediate text buffer,
16870  // hold the listener until composition is done.
16871  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16872  if (!$sniffer.android) {
16873    var composing = false;
16874
16875    element.on('compositionstart', function(data) {
16876      composing = true;
16877    });
16878
16879    element.on('compositionend', function() {
16880      composing = false;
16881      listener();
16882    });
16883  }
16884
16885  var listener = function(ev) {
16886    if (composing) return;
16887    var value = element.val();
16888
16889    // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
16890    // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
16891    // IE also sends input events for other non-input-related things, (such as focusing on a
16892    // form control), so this change is not entirely enough to solve this.
16893    if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
16894      placeholder = element[0].placeholder;
16895      return;
16896    }
16897
16898    // By default we will trim the value
16899    // If the attribute ng-trim exists we will avoid trimming
16900    // e.g. <input ng-model="foo" ng-trim="false">
16901    if (toBoolean(attr.ngTrim || 'T')) {
16902      value = trim(value);
16903    }
16904
16905    // If a control is suffering from bad input, browsers discard its value, so it may be
16906    // necessary to revalidate even if the control's value is the same empty value twice in
16907    // a row.
16908    var revalidate = validity && ctrl.$$hasNativeValidators;
16909    if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
16910      if (scope.$$phase) {
16911        ctrl.$setViewValue(value);
16912      } else {
16913        scope.$apply(function() {
16914          ctrl.$setViewValue(value);
16915        });
16916      }
16917    }
16918  };
16919
16920  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
16921  // input event on backspace, delete or cut
16922  if ($sniffer.hasEvent('input')) {
16923    element.on('input', listener);
16924  } else {
16925    var timeout;
16926
16927    var deferListener = function() {
16928      if (!timeout) {
16929        timeout = $browser.defer(function() {
16930          listener();
16931          timeout = null;
16932        });
16933      }
16934    };
16935
16936    element.on('keydown', function(event) {
16937      var key = event.keyCode;
16938
16939      // ignore
16940      //    command            modifiers                   arrows
16941      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
16942
16943      deferListener();
16944    });
16945
16946    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
16947    if ($sniffer.hasEvent('paste')) {
16948      element.on('paste cut', deferListener);
16949    }
16950  }
16951
16952  // if user paste into input using mouse on older browser
16953  // or form autocomplete on newer browser, we need "change" event to catch it
16954  element.on('change', listener);
16955
16956  ctrl.$render = function() {
16957    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
16958  };
16959
16960  // pattern validator
16961  var pattern = attr.ngPattern,
16962      patternValidator,
16963      match;
16964
16965  if (pattern) {
16966    var validateRegex = function(regexp, value) {
16967      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
16968    };
16969    match = pattern.match(/^\/(.*)\/([gim]*)$/);
16970    if (match) {
16971      pattern = new RegExp(match[1], match[2]);
16972      patternValidator = function(value) {
16973        return validateRegex(pattern, value);
16974      };
16975    } else {
16976      patternValidator = function(value) {
16977        var patternObj = scope.$eval(pattern);
16978
16979        if (!patternObj || !patternObj.test) {
16980          throw minErr('ngPattern')('noregexp',
16981            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
16982            patternObj, startingTag(element));
16983        }
16984        return validateRegex(patternObj, value);
16985      };
16986    }
16987
16988    ctrl.$formatters.push(patternValidator);
16989    ctrl.$parsers.push(patternValidator);
16990  }
16991
16992  // min length validator
16993  if (attr.ngMinlength) {
16994    var minlength = int(attr.ngMinlength);
16995    var minLengthValidator = function(value) {
16996      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
16997    };
16998
16999    ctrl.$parsers.push(minLengthValidator);
17000    ctrl.$formatters.push(minLengthValidator);
17001  }
17002
17003  // max length validator
17004  if (attr.ngMaxlength) {
17005    var maxlength = int(attr.ngMaxlength);
17006    var maxLengthValidator = function(value) {
17007      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
17008    };
17009
17010    ctrl.$parsers.push(maxLengthValidator);
17011    ctrl.$formatters.push(maxLengthValidator);
17012  }
17013}
17014
17015var numberBadFlags = ['badInput'];
17016
17017function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17018  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17019
17020  ctrl.$parsers.push(function(value) {
17021    var empty = ctrl.$isEmpty(value);
17022    if (empty || NUMBER_REGEXP.test(value)) {
17023      ctrl.$setValidity('number', true);
17024      return value === '' ? null : (empty ? value : parseFloat(value));
17025    } else {
17026      ctrl.$setValidity('number', false);
17027      return undefined;
17028    }
17029  });
17030
17031  addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
17032
17033  ctrl.$formatters.push(function(value) {
17034    return ctrl.$isEmpty(value) ? '' : '' + value;
17035  });
17036
17037  if (attr.min) {
17038    var minValidator = function(value) {
17039      var min = parseFloat(attr.min);
17040      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
17041    };
17042
17043    ctrl.$parsers.push(minValidator);
17044    ctrl.$formatters.push(minValidator);
17045  }
17046
17047  if (attr.max) {
17048    var maxValidator = function(value) {
17049      var max = parseFloat(attr.max);
17050      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
17051    };
17052
17053    ctrl.$parsers.push(maxValidator);
17054    ctrl.$formatters.push(maxValidator);
17055  }
17056
17057  ctrl.$formatters.push(function(value) {
17058    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
17059  });
17060}
17061
17062function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17063  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17064
17065  var urlValidator = function(value) {
17066    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
17067  };
17068
17069  ctrl.$formatters.push(urlValidator);
17070  ctrl.$parsers.push(urlValidator);
17071}
17072
17073function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17074  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17075
17076  var emailValidator = function(value) {
17077    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
17078  };
17079
17080  ctrl.$formatters.push(emailValidator);
17081  ctrl.$parsers.push(emailValidator);
17082}
17083
17084function radioInputType(scope, element, attr, ctrl) {
17085  // make the name unique, if not defined
17086  if (isUndefined(attr.name)) {
17087    element.attr('name', nextUid());
17088  }
17089
17090  element.on('click', function() {
17091    if (element[0].checked) {
17092      scope.$apply(function() {
17093        ctrl.$setViewValue(attr.value);
17094      });
17095    }
17096  });
17097
17098  ctrl.$render = function() {
17099    var value = attr.value;
17100    element[0].checked = (value == ctrl.$viewValue);
17101  };
17102
17103  attr.$observe('value', ctrl.$render);
17104}
17105
17106function checkboxInputType(scope, element, attr, ctrl) {
17107  var trueValue = attr.ngTrueValue,
17108      falseValue = attr.ngFalseValue;
17109
17110  if (!isString(trueValue)) trueValue = true;
17111  if (!isString(falseValue)) falseValue = false;
17112
17113  element.on('click', function() {
17114    scope.$apply(function() {
17115      ctrl.$setViewValue(element[0].checked);
17116    });
17117  });
17118
17119  ctrl.$render = function() {
17120    element[0].checked = ctrl.$viewValue;
17121  };
17122
17123  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
17124  ctrl.$isEmpty = function(value) {
17125    return value !== trueValue;
17126  };
17127
17128  ctrl.$formatters.push(function(value) {
17129    return value === trueValue;
17130  });
17131
17132  ctrl.$parsers.push(function(value) {
17133    return value ? trueValue : falseValue;
17134  });
17135}
17136
17137
17138/**
17139 * @ngdoc directive
17140 * @name textarea
17141 * @restrict E
17142 *
17143 * @description
17144 * HTML textarea element control with angular data-binding. The data-binding and validation
17145 * properties of this element are exactly the same as those of the
17146 * {@link ng.directive:input input element}.
17147 *
17148 * @param {string} ngModel Assignable angular expression to data-bind to.
17149 * @param {string=} name Property name of the form under which the control is published.
17150 * @param {string=} required Sets `required` validation error key if the value is not entered.
17151 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17152 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17153 *    `required` when you want to data-bind to the `required` attribute.
17154 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17155 *    minlength.
17156 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17157 *    maxlength.
17158 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17159 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17160 *    patterns defined as scope expressions.
17161 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17162 *    interaction with the input element.
17163 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17164 */
17165
17166
17167/**
17168 * @ngdoc directive
17169 * @name input
17170 * @restrict E
17171 *
17172 * @description
17173 * HTML input element control with angular data-binding. Input control follows HTML5 input types
17174 * and polyfills the HTML5 validation behavior for older browsers.
17175 *
17176 * @param {string} ngModel Assignable angular expression to data-bind to.
17177 * @param {string=} name Property name of the form under which the control is published.
17178 * @param {string=} required Sets `required` validation error key if the value is not entered.
17179 * @param {boolean=} ngRequired Sets `required` attribute if set to true
17180 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17181 *    minlength.
17182 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17183 *    maxlength.
17184 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17185 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17186 *    patterns defined as scope expressions.
17187 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17188 *    interaction with the input element.
17189 *
17190 * @example
17191    <example name="input-directive">
17192      <file name="index.html">
17193       <script>
17194         function Ctrl($scope) {
17195           $scope.user = {name: 'guest', last: 'visitor'};
17196         }
17197       </script>
17198       <div ng-controller="Ctrl">
17199         <form name="myForm">
17200           User name: <input type="text" name="userName" ng-model="user.n
17200ame" required>
17201           <span class="error" ng-show="myForm.userName.$error.required">
17202             Required!</span><br>
17203           Last name: <input type="text" name="lastName" ng-model="user.last"
17204             ng-minlength="3" ng-maxlength="10">
17205           <span class="error" ng-show="myForm.lastName.$error.minlength">
17206             Too short!</span>
17207           <span class="error" ng-show="myForm.lastName.$error.maxlength">
17208             Too long!</span><br>
17209         </form>
17210         <hr>
17211         <tt>user = {{user}}</tt><br/>
17212         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
17213         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
17214         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
17215         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
17216         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
17217         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
17218         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
17219         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
17220       </div>
17221      </file>
17222      <file name="protractor.js" type="protractor">
17223        var user = element(by.binding('{{user}}'));
17224        var userNameValid = element(by.binding('myForm.userName.$valid'));
17225        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
17226        var lastNameError = element(by.binding('myForm.lastName.$error'));
17227        var formValid = element(by.binding('myForm.$valid'));
17228        var userNameInput = element(by.model('user.name'));
17229        var userLastInput = element(by.model('user.last'));
17230
17231        it('should initialize to model', function() {
17232          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
17233          expect(userNameValid.getText()).toContain('true');
17234          expect(formValid.getText()).toContain('true');
17235        });
17236
17237        it('should be invalid if empty when required', function() {
17238          userNameInput.clear();
17239          userNameInput.sendKeys('');
17240
17241          expect(user.getText()).toContain('{"last":"visitor"}');
17242          expect(userNameValid.getText()).toContain('false');
17243          expect(formValid.getText()).toContain('false');
17244        });
17245
17246        it('should be valid if empty when min length is set', function() {
17247          userLastInput.clear();
17248          userLastInput.sendKeys('');
17249
17250          expect(user.getText()).toContain('{"name":"guest","last":""}');
17251          expect(lastNameValid.getText()).toContain('true');
17252          expect(formValid.getText()).toContain('true');
17253        });
17254
17255        it('should be invalid if less than required min length', function() {
17256          userLastInput.clear();
17257          userLastInput.sendKeys('xx');
17258
17259          expect(user.getText()).toContain('{"name":"guest"}');
17260          expect(lastNameValid.getText()).toContain('false');
17261          expect(lastNameError.getText()).toContain('minlength');
17262          expect(formValid.getText()).toContain('false');
17263        });
17264
17265        it('should be invalid if longer than max length', function() {
17266          userLastInput.clear();
17267          userLastInput.sendKeys('some ridiculously long name');
17268
17269          expect(user.getText()).toContain('{"name":"guest"}');
17270          expect(lastNameValid.getText()).toContain('false');
17271          expect(lastNameError.getText()).toContain('maxlength');
17272          expect(formValid.getText()).toContain('false');
17273        });
17274      </file>
17275    </example>
17276 */
17277var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
17278  return {
17279    restrict: 'E',
17280    require: '?ngModel',
17281    link: function(scope, element, attr, ctrl) {
17282      if (ctrl) {
17283        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17284                                                            $browser);
17285      }
17286    }
17287  };
17288}];
17289
17290var VALID_CLASS = 'ng-valid',
17291    INVALID_CLASS = 'ng-invalid',
17292    PRISTINE_CLASS = 'ng-pristine',
17293    DIRTY_CLASS = 'ng-dirty';
17294
17295/**
17296 * @ngdoc type
17297 * @name ngModel.NgModelController
17298 *
17299 * @property {string} $viewValue Actual string value in the view.
17300 * @property {*} $modelValue The value in the model, that the control is bound to.
17301 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17302       the control reads value from the DOM.  Each function is called, in turn, passing the value
17303       through to the next. The last return value is used to populate the model.
17304       Used to sanitize / convert the value as well as validation. For validation,
17305       the parsers should update the validity state using
17306       {@link ngModel.NgModelController#$setValidity $setValidity()},
17307       and return `undefined` for invalid values.
17308
17309 *
17310 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17311       the model value changes. Each function is called, in turn, passing the value through to the
17312       next. Used to format / convert values for display in the control and validation.
17313 * ```js
17314 * function formatter(value) {
17315 *   if (value) {
17316 *     return value.toUpperCase();
17317 *   }
17318 * }
17319 * ngModel.$formatters.push(formatter);
17320 * ```
17321 *
17322 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17323 *     view value has changed. It is called with no arguments, and its return value is ignored.
17324 *     This can be used in place of additional $watches against the model value.
17325 *
17326 * @property {Object} $error An object hash with all errors as keys.
17327 *
17328 * @property {boolean} $pristine True if user has not interacted with the control yet.
17329 * @property {boolean} $dirty True if user has already interacted with the control.
17330 * @property {boolean} $valid True if there is no error.
17331 * @property {boolean} $invalid True if at least one error on the control.
17332 *
17333 * @description
17334 *
17335 * `NgModelController` provides API for the `ng-model` directive. The controller contains
17336 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17337 * purposefully does not contain any logic which deals with DOM rendering or listening to
17338 * DOM events. Such DOM related logic should be provided by other directives which make use of
17339 * `NgModelController` for data-binding.
17340 *
17341 * ## Custom Control Example
17342 * This example shows how to use `NgModelController` with a custom control to achieve
17343 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17344 * collaborate together to achieve the desired result.
17345 *
17346 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17347 * contents be edited in place by the user.  This will not work on older browsers.
17348 *
17349 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
17350 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
17351 * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
17352 * that content using the `$sce` service.
17353 *
17354 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
17355    <file name="style.css">
17356      [contenteditable] {
17357        border: 1px solid black;
17358        background-color: white;
17359        min-height: 20px;
17360      }
17361
17362      .ng-invalid {
17363        border: 1px solid red;
17364      }
17365
17366    </file>
17367    <file name="script.js">
17368      angular.module('customControl', ['ngSanitize']).
17369        directive('contenteditable', ['$sce', function($sce) {
17370          return {
17371            restrict: 'A', // only activate on element attribute
17372            require: '?ngModel', // get a hold of NgModelController
17373            link: function(scope, element, attrs, ngModel) {
17374              if(!ngModel) return; // do nothing if no ng-model
17375
17376              // Specify how UI should be updated
17377              ngModel.$render = function() {
17378                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
17379              };
17380
17381              // Listen for change events to enable binding
17382              element.on('blur keyup change', function() {
17383                scope.$apply(read);
17384              });
17385              read(); // initialize
17386
17387              // Write data to the model
17388              function read() {
17389                var html = element.html();
17390                // When we clear the content editable the browser leaves a <br> behind
17391                // If strip-br attribute is provided then we strip this out
17392                if( attrs.stripBr && html == '<br>' ) {
17393                  html = '';
17394                }
17395                ngModel.$setViewValue(html);
17396              }
17397            }
17398          };
17399        }]);
17400    </file>
17401    <file name="index.html">
17402      <form name="myForm">
17403       <div contenteditable
17404            name="myWidget" ng-model="userContent"
17405            strip-br="true"
17406            required>Change me!</div>
17407        <span ng-show="myForm.myWidget.$error.required">Required!</span>
17408       <hr>
17409       <textarea ng-model="userContent"></textarea>
17410      </form>
17411    </file>
17412    <file name="protractor.js" type="protractor">
17413    it('should data-bind and become invalid', function() {
17414      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17415        // SafariDriver can't handle contenteditable
17416        // and Firefox driver can't clear contenteditables very well
17417        return;
17418      }
17419      var contentEditable = element(by.css('[contenteditable]'));
17420      var content = 'Change me!';
17421
17422      expect(contentEditable.getText()).toEqual(content);
17423
17424      contentEditable.clear();
17425      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17426      expect(contentEditable.getText()).toEqual('');
17427      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17428    });
17429    </file>
17430 * </example>
17431 *
17432 *
17433 */
17434var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17435    function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17436  this.$viewValue = Number.NaN;
17437  this.$modelValue = Number.NaN;
17438  this.$parsers = [];
17439  this.$formatters = [];
17440  this.$viewChangeListeners = [];
17441  this.$pristine = true;
17442  this.$dirty = false;
17443  this.$valid = true;
17444  this.$invalid = false;
17445  this.$name = $attr.name;
17446
17447  var ngModelGet = $parse($attr.ngModel),
17448      ngModelSet = ngModelGet.assign;
17449
17450  if (!ngModelSet) {
17451    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17452        $attr.ngModel, startingTag($element));
17453  }
17454
17455  /**
17456   * @ngdoc method
17457   * @name ngModel.NgModelController#$render
17458   *
17459   * @description
17460   * Called when the view needs to be updated. It is expected that the user of the ng-model
17461   * directive will implement this method.
17462   */
17463  this.$render = noop;
17464
17465  /**
17466   * @ngdoc method
17467   * @name ngModel.NgModelController#$isEmpty
17468   *
17469   * @description
17470   * This is called when we need to determine if the value of the input is empty.
17471   *
17472   * For instance, the required directive does this to work out if the input has data or not.
17473   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17474   *
17475   * You can override this for input directives whose concept of being empty is different to the
17476   * default. The `checkboxInputType` directive does this because in its case a value of `false`
17477   * implies empty.
17478   *
17479   * @param {*} value Reference to check.
17480   * @returns {boolean} True if `value` is empty.
17481   */
17482  this.$isEmpty = function(value) {
17483    return isUndefined(value) || value === '' || value === null || value !== value;
17484  };
17485
17486  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17487      invalidCount = 0, // used to easily determine if we are valid
17488      $error = this.$error = {};
17488 // keep invalid keys here
17489
17490
17491  // Setup initial state of the control
17492  $element.addClass(PRISTINE_CLASS);
17493  toggleValidCss(true);
17494
17495  // convenience method for easy toggling of classes
17496  function toggleValidCss(isValid, validationErrorKey) {
17497    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17498    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17499    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17500  }
17501
17502  /**
17503   * @ngdoc method
17504   * @name ngModel.NgModelController#$setValidity
17505   *
17506   * @description
17507   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17508   * does not notify form if given validator is already marked as invalid).
17509   *
17510   * This method should be called by validators - i.e. the parser or formatter functions.
17511   *
17512   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17513   *        to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
17514   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17515   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17516   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17517   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17518   */
17519  this.$setValidity = function(validationErrorKey, isValid) {
17520    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17521    // jshint -W018
17522    if ($error[validationErrorKey] === !isValid) return;
17523    // jshint +W018
17524
17525    if (isValid) {
17526      if ($error[validationErrorKey]) invalidCount--;
17527      if (!invalidCount) {
17528        toggleValidCss(true);
17529        this.$valid = true;
17530        this.$invalid = false;
17531      }
17532    } else {
17533      toggleValidCss(false);
17534      this.$invalid = true;
17535      this.$valid = false;
17536      invalidCount++;
17537    }
17538
17539    $error[validationErrorKey] = !isValid;
17540    toggleValidCss(isValid, validationErrorKey);
17541
17542    parentForm.$setValidity(validationErrorKey, isValid, this);
17543  };
17544
17545  /**
17546   * @ngdoc method
17547   * @name ngModel.NgModelController#$setPristine
17548   *
17549   * @description
17550   * Sets the control to its pristine state.
17551   *
17552   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17553   * state (ng-pristine class).
17554   */
17555  this.$setPristine = function () {
17556    this.$dirty = false;
17557    this.$pristine = true;
17558    $animate.removeClass($element, DIRTY_CLASS);
17559    $animate.addClass($element, PRISTINE_CLASS);
17560  };
17561
17562  /**
17563   * @ngdoc method
17564   * @name ngModel.NgModelController#$setViewValue
17565   *
17566   * @description
17567   * Update the view value.
17568   *
17569   * This method should be called when the view value changes, typically from within a DOM event handler.
17570   * For example {@link ng.directive:input input} and
17571   * {@link ng.directive:select select} directives call it.
17572   *
17573   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17574   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17575   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17576   *
17577   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17578   *
17579   * Note that calling this function does not trigger a `$digest`.
17580   *
17581   * @param {string} value Value from the view.
17582   */
17583  this.$setViewValue = function(value) {
17584    this.$viewValue = value;
17585
17586    // change to dirty
17587    if (this.$pristine) {
17588      this.$dirty = true;
17589      this.$pristine = false;
17590      $animate.removeClass($element, PRISTINE_CLASS);
17591      $animate.addClass($element, DIRTY_CLASS);
17592      parentForm.$setDirty();
17593    }
17594
17595    forEach(this.$parsers, function(fn) {
17596      value = fn(value);
17597    });
17598
17599    if (this.$modelValue !== value) {
17600      this.$modelValue = value;
17601      ngModelSet($scope, value);
17602      forEach(this.$viewChangeListeners, function(listener) {
17603        try {
17604          listener();
17605        } catch(e) {
17606          $exceptionHandler(e);
17607        }
17608      });
17609    }
17610  };
17611
17612  // model -> value
17613  var ctrl = this;
17614
17615  $scope.$watch(function ngModelWatch() {
17616    var value = ngModelGet($scope);
17617
17618    // if scope model value and ngModel value are out of sync
17619    if (ctrl.$modelValue !== value) {
17620
17621      var formatters = ctrl.$formatters,
17622          idx = formatters.length;
17623
17624      ctrl.$modelValue = value;
17625      while(idx--) {
17626        value = formatters[idx](value);
17627      }
17628
17629      if (ctrl.$viewValue !== value) {
17630        ctrl.$viewValue = value;
17631        ctrl.$render();
17632      }
17633    }
17634
17635    return value;
17636  });
17637}];
17638
17639
17640/**
17641 * @ngdoc directive
17642 * @name ngModel
17643 *
17644 * @element input
17645 *
17646 * @description
17647 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17648 * property on the scope using {@link ngModel.NgModelController NgModelController},
17649 * which is created and exposed by this directive.
17650 *
17651 * `ngModel` is responsible for:
17652 *
17653 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17654 *   require.
17655 * - Providing validation behavior (i.e. required, number, email, url).
17656 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17657 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17658 * - Registering the control with its parent {@link ng.directive:form form}.
17659 *
17660 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17661 * current scope. If the property doesn't already exist on this scope, it will be created
17662 * implicitly and added to the scope.
17663 *
17664 * For best practices on using `ngModel`, see:
17665 *
17666 *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
17667 *
17668 * For basic examples, how to use `ngModel`, see:
17669 *
17670 *  - {@link ng.directive:input input}
17671 *    - {@link input[text] text}
17672 *    - {@link input[checkbox] checkbox}
17673 *    - {@link input[radio] radio}
17674 *    - {@link input[number] number}
17675 *    - {@link input[email] email}
17676 *    - {@link input[url] url}
17677 *  - {@link ng.directive:select select}
17678 *  - {@link ng.directive:textarea textarea}
17679 *
17680 * # CSS classes
17681 * The following CSS classes are added and removed on the associated input/select/textarea element
17682 * depending on the validity of the model.
17683 *
17684 *  - `ng-valid` is set if the model is valid.
17685 *  - `ng-invalid` is set if the model is invalid.
17686 *  - `ng-pristine` is set if the model is pristine.
17687 *  - `ng-dirty` is set if the model is dirty.
17688 *
17689 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
17690 *
17691 * ## Animation Hooks
17692 *
17693 * Animations within models are triggered when any of the associated CSS classes are added and removed
17694 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
17695 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
17696 * The animations that are triggered within ngModel are similar to how they work in ngClass and
17697 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
17698 *
17699 * The following example shows a simple way to utilize CSS transitions to style an input element
17700 * that has been rendered as invalid after it has been validated:
17701 *
17702 * <pre>
17703 * //be sure to include ngAnimate as a module to hook into more
17704 * //advanced animations
17705 * .my-input {
17706 *   transition:0.5s linear all;
17707 *   background: white;
17708 * }
17709 * .my-input.ng-invalid {
17710 *   background: red;
17711 *   color:white;
17712 * }
17713 * </pre>
17714 *
17715 * @example
17716 * <example deps="angular-animate.js" animations="true" fixBase="true">
17717     <file name="index.html">
17718       <script>
17719        function Ctrl($scope) {
17720          $scope.val = '1';
17721        }
17722       </script>
17723       <style>
17724         .my-input {
17725           -webkit-transition:all linear 0.5s;
17726           transition:all linear 0.5s;
17727           background: transparent;
17728         }
17729         .my-input.ng-invalid {
17730           color:white;
17731           background: red;
17732         }
17733       </style>
17734       Update input to see transitions when valid/invalid.
17735       Integer is a valid value.
17736       <form name="testForm" ng-controller="Ctrl">
17737         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
17738       </form>
17739     </file>
17740 * </example>
17741 */
17742var ngModelDirective = function() {
17743  return {
17744    require: ['ngModel', '^?form'],
17745    controller: NgModelController,
17746    link: function(scope, element, attr, ctrls) {
17747      // notify others, especially parent forms
17748
17749      var modelCtrl = ctrls[0],
17750          formCtrl = ctrls[1] || nullFormCtrl;
17751
17752      formCtrl.$addControl(modelCtrl);
17753
17754      scope.$on('$destroy', function() {
17755        formCtrl.$removeControl(modelCtrl);
17756      });
17757    }
17758  };
17759};
17760
17761
17762/**
17763 * @ngdoc directive
17764 * @name ngChange
17765 *
17766 * @description
17767 * Evaluate the given expression when the user changes the input.
17768 * The expression is evaluated immediately, unlike the JavaScript onchange event
17769 * which only triggers at the end of a change (usually, when the user leaves the
17770 * form element or presses the return key).
17771 * The expression is not evaluated when the value change is coming from the model.
17772 *
17773 * Note, this directive requires `ngModel` to be present.
17774 *
17775 * @element input
17776 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17777 * in input value.
17778 *
17779 * @example
17780 * <example name="ngChange-directive">
17781 *   <file name="index.html">
17782 *     <script>
17783 *       function Controller($scope) {
17784 *         $scope.counter = 0;
17785 *         $scope.change = function() {
17786 *           $scope.counter++;
17787 *         };
17788 *       }
17789 *     </script>
17790 *     <div ng-controller="Controller">
17791 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17792 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17793 *       <label for="ng-change-example2">Confirmed</label><br />
17794 *       <tt>debug = {{confirmed}}</tt><br/>
17795 *       <tt>counter = {{counter}}</tt><br/>
17796 *     </div>
17797 *   </file>
17798 *   <file name="protractor.js" type="protractor">
17799 *     var counter = element(by.binding('counter'));
17800 *     var debug = element(by.binding('confirmed'));
17801 *
17802 *     it('should evaluate the expression if changing from view', function() {
17803 *       expect(counter.getText()).toContain('0');
17804 *
17805 *       element(by.id('ng-change-example1')).click();
17806 *
17807 *       expect(counter.getText()).toContain('1');
17808 *       expect(debug.getText()).toContain('true');
17809 *     });
17810 *
17811 *     it('should not evaluate the expression if changing from model', function() {
17812 *       element(by.id('ng-change-example2')).click();
17813
17814 *       expect(counter.getText()).toContain('0');
17815 *       expect(debug.getText()).toContain('true');
17816 *     });
17817 *   </file>
17818 * </example>
17819 */
17820var ngChangeDirective = valueFn({
17821  require: 'ngModel',
17822  link: function(scope, element, attr, ctrl) {
17823    ctrl.$viewChangeListeners.push(function() {
17824      scope.$eval(attr.ngChange);
17825    });
17826  }
17827});
17828
17829
17830var requiredDirective = function() {
17831  return {
17832    require: '?ngModel',
17833    link: function(scope, elm, attr, ctrl) {
17834      if (!ctrl) return;
17835      attr.required = true; // force truthy in case we are on non input element
17836
17837      var validator = function(value) {
17838        if (attr.required && ctrl.$isEmpty(value)) {
17839          ctrl.$setValidity('required', false);
17840          return;
17841        } else {
17842          ctrl.$setValidity('required', true);
17843          return value;
17844        }
17845      };
17846
17847      ctrl.$formatters.push(validator);
17848      ctrl.$parsers.unshift(validator);
17849
17850      attr.$observe('required', function() {
17851        validator(ctrl.$viewValue);
17852      });
17853    }
17854  };
17855};
17856
17857
17858/**
17859 * @ngdoc directive
17860 * @name ngList
17861 *
17862 * @description
17863 * Text input that converts between a delimited string and an array of strings. The delimiter
17864 * can be a fixed string (by default a comma) or a regular expression.
17865 *
17866 * @element input
17867 * @param {string=} ngList optional delimiter that should be used to split the value. If
17868 *   specified in form `/something/` then the value will be converted into a regular expression.
17869 *
17870 * @example
17871    <example name="ngList-directive">
17872      <file name="index.html">
17873       <script>
17874         function Ctrl($scope) {
17875           $scope.names = ['igor', 'misko', 'vojta'];
17876         }
17877       </script>
17878       <form name="myForm" ng-controller="Ctrl">
17879         List: <input name="namesInput" ng-model="names" ng-list required>
17880         <span class="error" ng-show="myForm.namesInput.$error.required">
17881           Required!</span>
17882         <br>
17883         <tt>names = {{names}}</tt><br/>
17884         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
17885         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
17886         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
17887         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
17888        </form>
17889      </file>
17890      <file name="protractor.js" type="protractor">
17891        var listInput = element(by.model('names'));
17892        var names = element(by.binding('{{names}}'));
17893        var valid = element(by.binding('myForm.namesInput.$valid'));
17894        var error = element(by.css('span.error'));
17895
17896        it('should initialize to model', function() {
17897          expect(names.getText()).toContain('["igor","misko","vojta"]');
17898          expect(valid.getText()).toContain('true');
17899          expect(error.getCssValue('display')).toBe('none');
17900        });
17901
17902        it('should be invalid if empty', function() {
17903          listInput.clear();
17904          listInput.sendKeys('');
17905
17906          expect(names.getText()).toContain('');
17907          expect(valid.getText()).toContain('false');
17908          expect(error.getCssValue('display')).not.toBe('none');        });
17909      </file>
17910    </example>
17911 */
17912var ngListDirective = function() {
17913  return {
17914    require: 'ngModel',
17915    link: function(scope, element, attr, ctrl) {
17916      var match = /\/(.*)\//.exec(attr.ngList),
17917          separator = match && new RegExp(match[1]) || attr.ngList || ',';
17918
17919      var parse = function(viewValue) {
17920        // If the viewValue is invalid (say required but empty) it will be `undefined`
17921        if (isUndefined(viewValue)) return;
17922
17923        var list = [];
17924
17925        if (viewValue) {
17926          forEach(viewValue.split(separator), function(value) {
17927            if (value) list.push(trim(value));
17928          });
17929        }
17930
17931        return list;
17932      };
17933
17934      ctrl.$parsers.push(parse);
17935      ctrl.$formatters.push(function(value) {
17936        if (isArray(value)) {
17937          return value.join(', ');
17938        }
17939
17940        return undefined;
17941      });
17942
17943      // Override the standard $isEmpty because an empty array means the input is empty.
17944      ctrl.$isEmpty = function(value) {
17945        return !value || !value.length;
17946      };
17947    }
17948  };
17949};
17950
17951
17952var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
17953/**
17954 * @ngdoc directive
17955 * @name ngValue
17956 *
17957 * @description
17958 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
17959 * that when the element is selected, the `ngModel` of that element is set to the
17960 * bound value.
17961 *
17962 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
17963 * shown below.
17964 *
17965 * @element input
17966 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
17967 *   of the `input` element
17968 *
17969 * @example
17970    <example name="ngValue-directive">
17971      <file name="index.html">
17972       <script>
17973          function Ctrl($scope) {
17974            $scope.names = ['pizza', 'unicorns', 'robots'];
17975            $scope.my = { favorite: 'unicorns' };
17976          }
17977       </script>
17978        <form ng-controller="Ctrl">
17979          <h2>Which is your favorite?</h2>
17980            <label ng-repeat="name in names" for="{{name}}">
17981              {{name}}
17982              <input type="radio"
17983                     ng-model="my.favorite"
17984                     ng-value="name"
17985                     id="{{name}}"
17986                     name="favorite">
17987            </label>
17988          <div>You chose {{my.favorite}}</div>
17989        </form>
17990      </file>
17991      <file name="protractor.js" type="protractor">
17992        var favorite = element(by.binding('my.favorite'));
17993
17994        it('should initialize to model', function() {
17995          expect(favorite.getText()).toContain('unicorns');
17996        });
17997        it('should bind the values to the inputs', function() {
17998          element.all(by.model('my.favorite')).get(0).click();
17999          expect(favorite.getText()).toContain('pizza');
18000        });
18001      </file>
18002    </example>
18003 */
18004var ngValueDirective = function() {
18005  return {
18006    priority: 100,
18007    compile: function(tpl, tplAttr) {
18008      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
18009        return function ngValueConstantLink(scope, elm, attr) {
18010          attr.$set('value', scope.$eval(attr.ngValue));
18011        };
18012      } else {
18013        return function ngValueLink(scope, elm, attr) {
18014          scope.$watch(attr.ngValue, function valueWatchAction(value) {
18015            attr.$set('value', value);
18016          });
18017        };
18018      }
18019    }
18020  };
18021};
18022
18023/**
18024 * @ngdoc directive
18025 * @name ngBind
18026 * @restrict AC
18027 *
18028 * @description
18029 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
18030 * with the value of a given expression, and to update the text content when the value of that
18031 * expression changes.
18032 *
18033 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
18034 * `{{ expression }}` which is similar but less verbose.
18035 *
18036 * It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
18037 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
18038 * element attribute, it makes the bindings invisible to the user while the page is loading.
18039 *
18040 * An alternative solution to this problem would be using the
18041 * {@link ng.directive:ngCloak ngCloak} directive.
18042 *
18043 *
18044 * @element ANY
18045 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
18046 *
18047 * @example
18048 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
18049   <example>
18050     <file name="index.html">
18051       <script>
18052         function Ctrl($scope) {
18053           $scope.name = 'Whirled';
18054         }
18055       </script>
18056       <div ng-controller="Ctrl">
18057         Enter name: <input type="text" ng-model="name"><br>
18058         Hello <span ng-bind="name"></span>!
18059       </div>
18060     </file>
18061     <file name="protractor.js" type="protractor">
18062       it('should check ng-bind', function() {
18063         var nameInput = element(by.model('name'));
18064
18065         expect(element(by.binding('name')).getText()).toBe('Whirled');
18066         nameInput.clear();
18067         nameInput.sendKeys('world');
18068         expect(element(by.binding('name')).getText()).toBe('world');
18069       });
18070     </file>
18071   </example>
18072 */
18073var ngBindDirective = ngDirective({
18074  compile: function(templateElement) {
18075    templateElement.addClass('ng-binding');
18076    return function (scope, element, attr) {
18077      element.data('$binding', attr.ngBind);
18078      scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
18079        // We are purposefully using == here rather than === because we want to
18080        // catch when value is "null or undefined"
18081        // jshint -W041
18082        element.text(value == undefined ? '' : value);
18083      });
18084    };
18085  }
18086});
18087
18088
18089/**
18090 * @ngdoc directive
18091 * @name ngBindTemplate
18092 *
18093 * @description
18094 * The `ngBindTemplate` directive specifies that the element
18095 * text content should be replaced with the interpolation of the template
18096 * in the `ngBindTemplate` attribute.
18097 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
18098 * expressions. This directive is needed since some HTML elements
18099 * (such as TITLE and OPTION) cannot contain SPAN elements.
18100 *
18101 * @element ANY
18102 * @param {string} ngBindTemplate template of form
18103 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
18104 *
18105 * @example
18106 * Try it here: enter text in text box and watch the greeting change.
18107   <example>
18108     <file name="index.html">
18109       <script>
18110         function Ctrl($scope) {
18111           $scope.salutation = 'Hello';
18112           $scope.name = 'World';
18113         }
18114       </script>
18115       <div ng-controller="Ctrl">
18116        Salutation: <input type="text" ng-model="salutation"><br>
18117        Name: <input type="text" ng-model="name"><br>
18118        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
18119       </div>
18120     </file>
18121     <file name="protractor.js" type="protractor">
18122       it('should check ng-bind', function() {
18123         var salutationElem = element(by.binding('salutation'));
18124         var salutationInput = element(by.model('salutation'));
18125         var nameInput = element(by.model('name'));
18126
18127         expect(salutationElem.getText()).toBe('Hello World!');
18128
18129         salutationInput.clear();
18130         salutationInput.sendKeys('Greetings');
18131         nameInput.clear();
18132         nameInput.sendKeys('user');
18133
18134         expect(salutationElem.getText()).toBe('Greetings user!');
18135       });
18136     </file>
18137   </example>
18138 */
18139var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
18140  return function(scope, element, attr) {
18141    // TODO: move this to scenario runner
18142    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
18143    element.addClass('ng-binding').data('$binding', interpolateFn);
18144    attr.$observe('ngBindTemplate', function(value) {
18145      element.text(value);
18146    });
18147  };
18148}];
18149
18150
18151/**
18152 * @ngdoc directive
18153 * @name ngBindHtml
18154 *
18155 * @description
18156 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
18157 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
18158 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
18159 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
18160 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
18161 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
18162 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
18163 *
18164 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
18165 * will have an exception (instead of an exploit.)
18166 *
18167 * @element ANY
18168 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18169 *
18170 * @example
18171   Try it here: enter text in text box and watch the greeting change.
18172
18173   <example module="ngBindHtmlExample" deps="angular-sanitize.js">
18174     <file name="index.html">
18175       <div ng-controller="ngBindHtmlCtrl">
18176        <p ng-bind-html="myHTML"></p>
18177       </div>
18178     </file>
18179
18180     <file name="script.js">
18181       angular.module('ngBindHtmlExample', ['ngSanitize'])
18182
18183       .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
18184         $scope.myHTML =
18185            'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
18186       }]);
18187     </file>
18188
18189     <file name="protractor.js" type="protractor">
18190       it('should check ng-bind-html', function() {
18191         expect(element(by.binding('myHTML')).getText()).toBe(
18192             'I am an HTMLstring with links! and other stuff');
18193       });
18194     </file>
18195   </example>
18196 */
18197var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
18198  return function(scope, element, attr) {
18199    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
18200
18201    var parsed = $parse(attr.ngBindHtml);
18202    function getStringValue() { return (parsed(scope) || '').toString(); }
18203
18204    scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
18205      element.html($sce.getTrustedHtml(parsed(scope)) || '');
18206    });
18207  };
18208}];
18209
18210function classDirective(name, selector) {
18211  name = 'ngClass' + name;
18212  return ['$animate', function($animate) {
18213    return {
18214      restrict: 'AC',
18215      link: function(scope, element, attr) {
18216        var oldVal;
18217
18218        scope.$watch(attr[name], ngClassWatchAction, true);
18219
18220        attr.$observe('class', function(value) {
18221          ngClassWatchAction(scope.$eval(attr[name]));
18222        });
18223
18224
18225        if (name !== 'ngClass') {
18226          scope.$watch('$index', function($index, old$index) {
18227            // jshint bitwise: false
18228            var mod = $index & 1;
18229            if (mod !== (old$index & 1)) {
18230              var classes = arrayClasses(scope.$eval(attr[name]));
18231              mod === selector ?
18232                addClasses(classes) :
18233                removeClasses(classes);
18234            }
18235          });
18236        }
18237
18238        function addClasses(classes) {
18239          var newClasses = digestClassCounts(classes, 1);
18240          attr.$addClass(newClasses);
18241        }
18242
18243        function removeClasses(classes) {
18244          var newClasses = digestClassCounts(classes, -1);
18245          attr.$removeClass(newClasses);
18246        }
18247
18248        function digestClassCounts (classes, count) {
18249          var classCounts = element.data('$classCounts') || {};
18250          var classesToUpdate = [];
18251          forEach(classes, function (className) {
18252            if (count > 0 || classCounts[className]) {
18253              classCounts[className] = (classCounts[className] || 0) + count;
18254              if (classCounts[className] === +(count > 0)) {
18255                classesToUpdate.push(className);
18256              }
18257            }
18258          });
18259          element.data('$classCounts', classCounts);
18260          return classesToUpdate.join(' ');
18261        }
18262
18263        function updateClasses (oldClasses, newClasses) {
18264          var toAdd = arrayDifference(newClasses, oldClasses);
18265          var toRemove = arrayDifference(oldClasses, newClasses);
18266          toRemove = digestClassCounts(toRemove, -1);
18267          toAdd = digestClassCounts(toAdd, 1);
18268
18269          if (toAdd.length === 0) {
18270            $animate.removeClass(element, toRemove);
18271          } else if (toRemove.length === 0) {
18272            $animate.addClass(element, toAdd);
18273          } else {
18274            $animate.setClass(element, toAdd, toRemove);
18275          }
18276        }
18277
18278        function ngClassWatchAction(newVal) {
18279          if (selector === true || scope.$index % 2 === selector) {
18280            var newClasses = arrayClasses(newVal || []);
18281            if (!oldVal) {
18282              addClasses(newClasses);
18283            } else if (!equals(newVal,oldVal)) {
18284              var oldClasses = arrayClasses(oldVal);
18285              updateClasses(oldClasses, newClasses);
18286            }
18287          }
18288          oldVal = shallowCopy(newVal);
18289        }
18290      }
18291    };
18292
18293    function arrayDifference(tokens1, tokens2) {
18294      var values = [];
18295
18296      outer:
18297      for(var i = 0; i < tokens1.length; i++) {
18298        var token = tokens1[i];
18299        for(var j = 0; j < tokens2.length; j++) {
18300          if(token == tokens2[j]) continue outer;
18301        }
18302        values.push(token);
18303      }
18304      return values;
18305    }
18306
18307    function arrayClasses (classVal) {
18308      if (isArray(classVal)) {
18309        return classVal;
18310      } else if (isString(classVal)) {
18311        return classVal.split(' ');
18312      } else if (isObject(classVal)) {
18313        var classes = [], i = 0;
18314        forEach(classVal, function(v, k) {
18315          if (v) {
18316            classes = classes.concat(k.split(' '));
18317          }
18318        });
18319        return classes;
18320      }
18321      return classVal;
18322    }
18323  }];
18324}
18325
18326/**
18327 * @ngdoc directive
18328 * @name ngClass
18329 * @restrict AC
18330 *
18331 * @description
18332 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18333 * an expression that represents all classes to be added.
18334 *
18335 * The directive operates in three different ways, depending on which of three types the expression
18336 * evaluates to:
18337 *
18338 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18339 * names.
18340 *
18341 * 2. If the expression evaluates to an array, each element of the array should be a string that is
18342 * one or more space-delimited class names.
18343 *
18344 * 3. If the expression evaluates to an object, then for each key-value pair of the
18345 * object with a truthy value the corresponding key is used as a class name.
18346 *
18347 * The directive won't add duplicate classes if a particular class was already set.
18348 *
18349 * When the expression changes, the previously added classes are removed and only then the
18350 * new classes are added.
18351 *
18352 * @animations
18353 * add - happens just before the class is applied to the element
18354 * remove - happens just before the class is removed from the element
18355 *
18356 * @element ANY
18357 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18358 *   of the evaluation can be a string representing space delimited class
18359 *   names, an array, or a map of class names to boolean values. In the case of a map, the
18360 *   names of the properties whose values are truthy will be added as css classes to the
18361 *   element.
18362 *
18363 * @example Example that demonstrates basic bindings via ngClass directive.
18364   <example>
18365     <file name="index.html">
18366       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18367       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18368       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18369       <input type="checkbox" ng-model="error"> error (apply "red" class)
18370       <hr>
18371       <p ng-class="style">Using String Syntax</p>
18372       <input type="text" ng-model="style" placeholder="Type: bold strike red">
18373       <hr>
18374       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18375       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18376       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18377       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18378     </file>
18379     <file name="style.css">
18380       .strike {
18381         text-decoration: line-through;
18382       }
18383       .bold {
18384           font-weight: bold;
18385       }
18386       .red {
18387           color: red;
18388       }
18389     </file>
18390     <file name="protractor.js" type="protractor">
18391       var ps = element.all(by.css('p'));
18392
18393       it('should let you toggle the class', function() {
18394
18395         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18396         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18397
18398         element(by.model('important')).click();
18399         expect(ps.first().getAttribute('class')).toMatch(/bold/);
18400
18401         element(by.model('error')).click();
18402         expect(ps.first().getAttribute('class')).toMatch(/red/);
18403       });
18404
18405       it('should let you toggle string example', function() {
18406         expect(ps.get(1).getAttribute('class')).toBe('');
18407         element(by.model('style')).clear();
18408         element(by.model('style')).sendKeys('red');
18409         expect(ps.get(1).getAttribute('class')).toBe('red');
18410       });
18411
18412       it('array example should have 3 classes', function() {
18413         expect(ps.last().getAttribute('class')).toBe('');
18414         element(by.model('style1')).sendKeys('bold');
18415         element(by.model('style2')).sendKeys('strike');
18416         element(by.model('style3')).sendKeys('red');
18417         expect(ps.last().getAttribute('class')).toBe('bold strike red');
18418       });
18419     </file>
18420   </example>
18421
18422   ## Animations
18423
18424   The example below demonstrates how to perform animations using ngClass.
18425
18426   <example module="ngAnimate" deps="angular-animate.js" animations="true">
18427     <file name="index.html">
18428      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18429      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18430      <br>
18431      <span class="base-class" ng-class="myVar">Sample Text</span>
18432     </file>
18433     <file name="style.css">
18434       .base-class {
18435         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18436         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18437       }
18438
18439       .base-class.my-class {
18440         color: red;
18441         font-size:3em;
18442       }
18443     </file>
18444     <file name="protractor.js" type="protractor">
18445       it('should check ng-class', function() {
18446         expect(element(by.css('.base-class')).getAttribute('class')).not.
18447           toMatch(/my-class/);
18448
18449         element(by.id('setbtn')).click();
18450
18451         expect(element(by.css('.base-class')).getAttribute('class')).
18452           toMatch(/my-class/);
18453
18454         element(by.id('clearbtn')).click();
18455
18456         expect(element(by.css('.base-class')).getAttribute('class')).not.
18457           toMatch(/my-class/);
18458       });
18459     </file>
18460   </example>
18461
18462
18463   ## ngClass and pre-existing CSS3 Transitions/Animations
18464   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18465   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18466   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18467   to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18468   {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18469 */
18470var ngClassDirective = classDirective('', true);
18471
18472/**
18473 * @ngdoc directive
18474 * @name ngClassOdd
18475 * @restrict AC
18476 *
18477 * @description
18478 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18479 * {@link ng.directive:ngClass ngClass}, except they work in
18480 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18481 *
18482 * This directive can be applied only within the scope of an
18483 * {@link ng.directive:ngRepeat ngRepeat}.
18484 *
18485 * @element ANY
18486 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18487 *   of the evaluation can be a string representing space delimited class names or an array.
18488 *
18489 * @example
18490   <example>
18491     <file name="index.html">
18492        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18493          <li ng-repeat="name in names">
18494           <span ng-class-odd="'odd'" ng-class-even="'even'">
18495             {{name}}
18496           </span>
18497          </li>
18498        </ol>
18499     </file>
18500     <file name="style.css">
18501       .odd {
18502         color: red;
18503       }
18504       .even {
18505         color: blue;
18506       }
18507     </file>
18508     <file name="protractor.js" type="protractor">
18509       it('should check ng-class-odd and ng-class-even', function() {
18510         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18511           toMatch(/odd/);
18512         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18513           toMatch(/even/);
18514       });
18515     </file>
18516   </example>
18517 */
18518var ngClassOddDirective = classDirective('Odd', 0);
18519
18520/**
18521 * @ngdoc directive
18522 * @name ngClassEven
18523 * @restrict AC
18524 *
18525 * @description
18526 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18527 * {@link ng.directive:ngClass ngClass}, except they work in
18528 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18529 *
18530 * This directive can be applied only within the scope of an
18531 * {@link ng.directive:ngRepeat ngRepeat}.
18532 *
18533 * @element ANY
18534 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18535 *   result of the evaluation can be a string representing space delimited class names or an array.
18536 *
18537 * @example
18538   <example>
18539     <file name="index.html">
18540        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18541          <li ng-repeat="name in names">
18542           <span ng-class-odd="'odd'" ng-class-even="'even'">
18543             {{name}} &nbsp; &nbsp; &nbsp;
18544           </span>
18545          </li>
18546        </ol>
18547     </file>
18548     <file name="style.css">
18549       .odd {
18550         color: red;
18551       }
18552       .even {
18553         color: blue;
18554       }
18555     </file>
18556     <file name="protractor.js" type="protractor">
18557       it('should check ng-class-odd and ng-class-even', function() {
18558         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18559           toMatch(/odd/);
18560         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18561           toMatch(/even/);
18562       });
18563     </file>
18564   </example>
18565 */
18566var ngClassEvenDirective = classDirective('Even', 1);
18567
18568/**
18569 * @ngdoc directive
18570 * @name ngCloak
18571 * @restrict AC
18572 *
18573 * @description
18574 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18575 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18576 * directive to avoid the undesirable flicker effect caused by the html template display.
18577 *
18578 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18579 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18580 * of the browser view.
18581 *
18582 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18583 * `angular.min.js`.
18584 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18585 *
18586 * ```css
18587 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18588 *   display: none !important;
18589 * }
18590 * ```
18591 *
18592 * When this css rule is loaded by the browser, all html elements (including their children) that
18593 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18594 * during the compilation of the template it deletes the `ngCloak` element attribute, making
18595 * the compiled element visible.
18596 *
18597 * For the best result, the `angular.js` script must be loaded in the head section of the html
18598 * document; alternatively, the css rule above must be included in the external stylesheet of the
18599 * application.
18600 *
18601 * Legacy browsers, like IE7, do not provide attribute selector support (a
18601dded in CSS 2.1) so they
18602 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18603 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18604 *
18605 * @element ANY
18606 *
18607 * @example
18608   <example>
18609     <file name="index.html">
18610        <div id="template1" ng-cloak>{{ 'hello' }}</div>
18611        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18612     </file>
18613     <file name="protractor.js" type="protractor">
18614       it('should remove the template directive and css class', function() {
18615         expect($('#template1').getAttribute('ng-cloak')).
18616           toBeNull();
18617         expect($('#template2').getAttribute('ng-cloak')).
18618           toBeNull();
18619       });
18620     </file>
18621   </example>
18622 *
18623 */
18624var ngCloakDirective = ngDirective({
18625  compile: function(element, attr) {
18626    attr.$set('ngCloak', undefined);
18627    element.removeClass('ng-cloak');
18628  }
18629});
18630
18631/**
18632 * @ngdoc directive
18633 * @name ngController
18634 *
18635 * @description
18636 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18637 * supports the principles behind the Model-View-Controller design pattern.
18638 *
18639 * MVC components in angular:
18640 *
18641 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
18642 *   are accessed through bindings.
18643 * * View — The template (HTML with data bindings) that is rendered into the View.
18644 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18645 *   logic behind the application to decorate the scope with functions and values
18646 *
18647 * Note that you can also attach controllers to the DOM by declaring it in a route definition
18648 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18649 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18650 * and executed twice.
18651 *
18652 * @element ANY
18653 * @scope
18654 * @param {expression} ngController Name of a globally accessible constructor function or an
18655 *     {@link guide/expression expression} that on the current scope evaluates to a
18656 *     constructor function. The controller instance can be published into a scope property
18657 *     by specifying `as propertyName`.
18658 *
18659 * @example
18660 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18661 * greeting are methods declared on the controller (see source tab). These methods can
18662 * easily be called from the angular markup. Any changes to the data are automatically reflected
18663 * in the View without the need for a manual update.
18664 *
18665 * Two different declaration styles are included below:
18666 *
18667 * * one binds methods and properties directly onto the controller using `this`:
18668 * `ng-controller="SettingsController1 as settings"`
18669 * * one injects `$scope` into the controller:
18670 * `ng-controller="SettingsController2"`
18671 *
18672 * The second option is more common in the Angular community, and is generally used in boilerplates
18673 * and in this guide. However, there are advantages to binding properties directly to the controller
18674 * and avoiding scope.
18675 *
18676 * * Using `controller as` makes it obvious which controller you are accessing in the template when
18677 * multiple controllers apply to an element.
18678 * * If you are writing your controllers as classes you have easier access to the properties and
18679 * methods, which will appear on the scope, from inside the controller code.
18680 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
18681 * inheritance masking primitives.
18682 *
18683 * This example demonstrates the `controller as` syntax.
18684 *
18685 * <example name="ngControllerAs">
18686 *   <file name="index.html">
18687 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18688 *      Name: <input type="text" ng-model="settings.name"/>
18689 *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18690 *      Contact:
18691 *      <ul>
18692 *        <li ng-repeat="contact in settings.contacts">
18693 *          <select ng-model="contact.type">
18694 *             <option>phone</option>
18695 *             <option>email</option>
18696 *          </select>
18697 *          <input type="text" ng-model="contact.value"/>
18698 *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18699 *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18700 *        </li>
18701 *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18702 *     </ul>
18703 *    </div>
18704 *   </file>
18705 *   <file name="app.js">
18706 *    function SettingsController1() {
18707 *      this.name = "John Smith";
18708 *      this.contacts = [
18709 *        {type: 'phone', value: '408 555 1212'},
18710 *        {type: 'email', value: '[email protected]'} ];
18711 *    }
18712 *
18713 *    SettingsController1.prototype.greet = function() {
18714 *      alert(this.name);
18715 *    };
18716 *
18717 *    SettingsController1.prototype.addContact = function() {
18718 *      this.contacts.push({type: 'email', value: '[email protected]'});
18719 *    };
18720 *
18721 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
18722 *     var index = this.contacts.indexOf(contactToRemove);
18723 *      this.contacts.splice(index, 1);
18724 *    };
18725 *
18726 *    SettingsController1.prototype.clearContact = function(contact) {
18727 *      contact.type = 'phone';
18728 *      contact.value = '';
18729 *    };
18730 *   </file>
18731 *   <file name="protractor.js" type="protractor">
18732 *     it('should check controller as', function() {
18733 *       var container = element(by.id('ctrl-as-exmpl'));
18734 *         expect(container.findElement(by.model('settings.name'))
18735 *           .getAttribute('value')).toBe('John Smith');
18736 *
18737 *       var firstRepeat =
18738 *           container.findElement(by.repeater('contact in settings.contacts').row(0));
18739 *       var secondRepeat =
18740 *           container.findElement(by.repeater('contact in settings.contacts').row(1));
18741 *
18742 *       expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18743 *           .toBe('408 555 1212');
18744 *
18745 *       expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18746 *           .toBe('[email protected]');
18747 *
18748 *       firstRepeat.findElement(by.linkText('clear')).click();
18749 *
18750 *       expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18751 *           .toBe('');
18752 *
18753 *       container.findElement(by.linkText('add')).click();
18754 *
18755 *       expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
18756 *           .findElement(by.model('contact.value'))
18757 *           .getAttribute('value'))
18758 *           .toBe('[email protected]');
18759 *     });
18760 *   </file>
18761 * </example>
18762 *
18763 * This example demonstrates the "attach to `$scope`" style of controller.
18764 *
18765 * <example name="ngController">
18766 *  <file name="index.html">
18767 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
18768 *     Name: <input type="text" ng-model="name"/>
18769 *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
18770 *     Contact:
18771 *     <ul>
18772 *       <li ng-repeat="contact in contacts">
18773 *         <select ng-model="contact.type">
18774 *            <option>phone</option>
18775 *            <option>email</option>
18776 *         </select>
18777 *         <input type="text" ng-model="contact.value"/>
18778 *         [ <a href="" ng-click="clearContact(contact)">clear</a>
18779 *         | <a href="" ng-click="removeContact(contact)">X</a> ]
18780 *       </li>
18781 *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18782 *    </ul>
18783 *   </div>
18784 *  </file>
18785 *  <file name="app.js">
18786 *   function SettingsController2($scope) {
18787 *     $scope.name = "John Smith";
18788 *     $scope.contacts = [
18789 *       {type:'phone', value:'408 555 1212'},
18790 *       {type:'email', value:'[email protected]'} ];
18791 *
18792 *     $scope.greet = function() {
18793 *       alert($scope.name);
18794 *     };
18795 *
18796 *     $scope.addContact = function() {
18797 *       $scope.contacts.push({type:'email', value:'[email protected]'});
18798 *     };
18799 *
18800 *     $scope.removeContact = function(contactToRemove) {
18801 *       var index = $scope.contacts.indexOf(contactToRemove);
18802 *       $scope.contacts.splice(index, 1);
18803 *     };
18804 *
18805 *     $scope.clearContact = function(contact) {
18806 *       contact.type = 'phone';
18807 *       contact.value = '';
18808 *     };
18809 *   }
18810 *  </file>
18811 *  <file name="protractor.js" type="protractor">
18812 *    it('should check controller', function() {
18813 *      var container = element(by.id('ctrl-exmpl'));
18814 *
18815 *      expect(container.findElement(by.model('name'))
18816 *          .getAttribute('value')).toBe('John Smith');
18817 *
18818 *      var firstRepeat =
18819 *          container.findElement(by.repeater('contact in contacts').row(0));
18820 *      var secondRepeat =
18821 *          container.findElement(by.repeater('contact in contacts').row(1));
18822 *
18823 *      expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18824 *          .toBe('408 555 1212');
18825 *      expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18826 *          .toBe('[email protected]');
18827 *
18828 *      firstRepeat.findElement(by.linkText('clear')).click();
18829 *
18830 *      expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18831 *          .toBe('');
18832 *
18833 *      container.findElement(by.linkText('add')).click();
18834 *
18835 *      expect(container.findElement(by.repeater('contact in contacts').row(2))
18836 *          .findElement(by.model('contact.value'))
18837 *          .getAttribute('value'))
18838 *          .toBe('[email protected]');
18839 *    });
18840 *  </file>
18841 *</example>
18842
18843 */
18844var ngControllerDirective = [function() {
18845  return {
18846    scope: true,
18847    controller: '@',
18848    priority: 500
18849  };
18850}];
18851
18852/**
18853 * @ngdoc directive
18854 * @name ngCsp
18855 *
18856 * @element html
18857 * @description
18858 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
18859 *
18860 * This is necessary when developing things like Google Chrome Extensions.
18861 *
18862 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
18863 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
18864 * any of these restrictions.
18865 *
18866 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
18867 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
18868 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
18869 * be raised.
18870 *
18871 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
18872 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
18873 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
18874 *
18875 * In order to use this feature put the `ngCsp` directive on the root element of the application.
18876 *
18877 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
18878 *
18879 * @example
18880 * This example shows how to apply the `ngCsp` directive to the `html` tag.
18881   ```html
18882     <!doctype html>
18883     <html ng-app ng-csp>
18884     ...
18885     ...
18886     </html>
18887   ```
18888 */
18889
18890// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
18891// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
18892// anywhere in the current doc
18893
18894/**
18895 * @ngdoc directive
18896 * @name ngClick
18897 *
18898 * @description
18899 * The ngClick directive allows you to specify custom behavior when
18900 * an element is clicked.
18901 *
18902 * @element ANY
18903 * @priority 0
18904 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
18905 * click. ({@link guide/expression#-event- Event object is available as `$event`})
18906 *
18907 * @example
18908   <example>
18909     <file name="index.html">
18910      <button ng-click="count = count + 1" ng-init="count=0">
18911        Increment
18912      </button>
18913      count: {{count}}
18914     </file>
18915     <file name="protractor.js" type="protractor">
18916       it('should check ng-click', function() {
18917         expect(element(by.binding('count')).getText()).toMatch('0');
18918         element(by.css('button')).click();
18919         expect(element(by.binding('count')).getText()).toMatch('1');
18920       });
18921     </file>
18922   </example>
18923 */
18924/*
18925 * A directive that allows creation of custom onclick handlers that are defined as angular
18926 * expressions and are compiled and executed within the current scope.
18927 *
18928 * Events that are handled via these handler are always configured not to propagate further.
18929 */
18930var ngEventDirectives = {};
18931forEach(
18932  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
18933  function(name) {
18934    var directiveName = directiveNormalize('ng-' + name);
18935    ngEventDirectives[directiveName] = ['$parse', function($parse) {
18936      return {
18937        compile: function($element, attr) {
18938          var fn = $parse(attr[directiveName]);
18939          return function ngEventHandler(scope, element) {
18940            element.on(lowercase(name), function(event) {
18941              scope.$apply(function() {
18942                fn(scope, {$event:event});
18943              });
18944            });
18945          };
18946        }
18947      };
18948    }];
18949  }
18950);
18951
18952/**
18953 * @ngdoc directive
18954 * @name ngDblclick
18955 *
18956 * @description
18957 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
18958 *
18959 * @element ANY
18960 * @priority 0
18961 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
18962 * a dblclick. (The Event object is available as `$event`)
18963 *
18964 * @example
18965   <example>
18966     <file name="index.html">
18967      <button ng-dblclick="count = count + 1" ng-init="count=0">
18968        Increment (on double click)
18969      </button>
18970      count: {{count}}
18971     </file>
18972   </example>
18973 */
18974
18975
18976/**
18977 * @ngdoc directive
18978 * @name ngMousedown
18979 *
18980 * @description
18981 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
18982 *
18983 * @element ANY
18984 * @priority 0
18985 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
18986 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
18987 *
18988 * @example
18989   <example>
18990     <file name="index.html">
18991      <button ng-mousedown="count = count + 1" ng-init="count=0">
18992        Increment (on mouse down)
18993      </button>
18994      count: {{count}}
18995     </file>
18996   </example>
18997 */
18998
18999
19000/**
19001 * @ngdoc directive
19002 * @name ngMouseup
19003 *
19004 * @description
19005 * Specify custom behavior on mouseup event.
19006 *
19007 * @element ANY
19008 * @priority 0
19009 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
19010 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
19011 *
19012 * @example
19013   <example>
19014     <file name="index.html">
19015      <button ng-mouseup="count = count + 1" ng-init="count=0">
19016        Increment (on mouse up)
19017      </button>
19018      count: {{count}}
19019     </file>
19020   </example>
19021 */
19022
19023/**
19024 * @ngdoc directive
19025 * @name ngMouseover
19026 *
19027 * @description
19028 * Specify custom behavior on mouseover event.
19029 *
19030 * @element ANY
19031 * @priority 0
19032 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
19033 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
19034 *
19035 * @example
19036   <example>
19037     <file name="index.html">
19038      <button ng-mouseover="count = count + 1" ng-init="count=0">
19039        Increment (when mouse is over)
19040      </button>
19041      count: {{count}}
19042     </file>
19043   </example>
19044 */
19045
19046
19047/**
19048 * @ngdoc directive
19049 * @name ngMouseenter
19050 *
19051 * @description
19052 * Specify custom behavior on mouseenter event.
19053 *
19054 * @element ANY
19055 * @priority 0
19056 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
19057 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
19058 *
19059 * @example
19060   <example>
19061     <file name="index.html">
19062      <button ng-mouseenter="count = count + 1" ng-init="count=0">
19063        Increment (when mouse enters)
19064      </button>
19065      count: {{count}}
19066     </file>
19067   </example>
19068 */
19069
19070
19071/**
19072 * @ngdoc directive
19073 * @name ngMouseleave
19074 *
19075 * @description
19076 * Specify custom behavior on mouseleave event.
19077 *
19078 * @element ANY
19079 * @priority 0
19080 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
19081 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
19082 *
19083 * @example
19084   <example>
19085     <file name="index.html">
19086      <button ng-mouseleave="count = count + 1" ng-init="count=0">
19087        Increment (when mouse leaves)
19088      </button>
19089      count: {{count}}
19090     </file>
19091   </example>
19092 */
19093
19094
19095/**
19096 * @ngdoc directive
19097 * @name ngMousemove
19098 *
19099 * @description
19100 * Specify custom behavior on mousemove event.
19101 *
19102 * @element ANY
19103 * @priority 0
19104 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
19105 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
19106 *
19107 * @example
19108   <example>
19109     <file name="index.html">
19110      <button ng-mousemove="count = count + 1" ng-init="count=0">
19111        Increment (when mouse moves)
19112      </button>
19113      count: {{count}}
19114     </file>
19115   </example>
19116 */
19117
19118
19119/**
19120 * @ngdoc directive
19121 * @name ngKeydown
19122 *
19123 * @description
19124 * Specify custom behavior on keydown event.
19125 *
19126 * @element ANY
19127 * @priority 0
19128 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
19129 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19130 *
19131 * @example
19132   <example>
19133     <file name="index.html">
19134      <input ng-keydown="count = count + 1" ng-init="count=0">
19135      key down count: {{count}}
19136     </file>
19137   </example>
19138 */
19139
19140
19141/**
19142 * @ngdoc directive
19143 * @name ngKeyup
19144 *
19145 * @description
19146 * Specify custom behavior on keyup event.
19147 *
19148 * @element ANY
19149 * @priority 0
19150 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
19151 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19152 *
19153 * @example
19154   <example>
19155     <file name="index.html">
19156       <p>Typing in the input box below updates the key count</p>
19157       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
19158
19159       <p>Typing in the input box below updates the keycode</p>
19160       <input ng-keyup="event=$event">
19161       <p>event keyCode: {{ event.keyCode }}</p>
19162       <p>event altKey: {{ event.altKey }}</p>
19163     </file>
19164   </example>
19165 */
19166
19167
19168/**
19169 * @ngdoc directive
19170 * @name ngKeypress
19171 *
19172 * @description
19173 * Specify custom behavior on keypress event.
19174 *
19175 * @element ANY
19176 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
19177 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
19178 * and can be interrogated for keyCode, altKey, etc.)
19179 *
19180 * @example
19181   <example>
19182     <file name="index.html">
19183      <input ng-keypress="count = count + 1" ng-init="count=0">
19184      key press count: {{count}}
19185     </file>
19186   </example>
19187 */
19188
19189
19190/**
19191 * @ngdoc directive
19192 * @name ngSubmit
19193 *
19194 * @description
19195 * Enables binding angular expressions to onsubmit events.
19196 *
19197 * Additionally it prevents the default action (which for form means 
19197sending the request to the
19198 * server and reloading the current page), but only if the form does not contain `action`,
19199 * `data-action`, or `x-action` attributes.
19200 *
19201 * @element form
19202 * @priority 0
19203 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
19204 * ({@link guide/expression#-event- Event object is available as `$event`})
19205 *
19206 * @example
19207   <example>
19208     <file name="index.html">
19209      <script>
19210        function Ctrl($scope) {
19211          $scope.list = [];
19212          $scope.text = 'hello';
19213          $scope.submit = function() {
19214            if ($scope.text) {
19215              $scope.list.push(this.text);
19216              $scope.text = '';
19217            }
19218          };
19219        }
19220      </script>
19221      <form ng-submit="submit()" ng-controller="Ctrl">
19222        Enter text and hit enter:
19223        <input type="text" ng-model="text" name="text" />
19224        <input type="submit" id="submit" value="Submit" />
19225        <pre>list={{list}}</pre>
19226      </form>
19227     </file>
19228     <file name="protractor.js" type="protractor">
19229       it('should check ng-submit', function() {
19230         expect(element(by.binding('list')).getText()).toBe('list=[]');
19231         element(by.css('#submit')).click();
19232         expect(element(by.binding('list')).getText()).toContain('hello');
19233         expect(element(by.input('text')).getAttribute('value')).toBe('');
19234       });
19235       it('should ignore empty strings', function() {
19236         expect(element(by.binding('list')).getText()).toBe('list=[]');
19237         element(by.css('#submit')).click();
19238         element(by.css('#submit')).click();
19239         expect(element(by.binding('list')).getText()).toContain('hello');
19240        });
19241     </file>
19242   </example>
19243 */
19244
19245/**
19246 * @ngdoc directive
19247 * @name ngFocus
19248 *
19249 * @description
19250 * Specify custom behavior on focus event.
19251 *
19252 * @element window, input, select, textarea, a
19253 * @priority 0
19254 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
19255 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
19256 *
19257 * @example
19258 * See {@link ng.directive:ngClick ngClick}
19259 */
19260
19261/**
19262 * @ngdoc directive
19263 * @name ngBlur
19264 *
19265 * @description
19266 * Specify custom behavior on blur event.
19267 *
19268 * @element window, input, select, textarea, a
19269 * @priority 0
19270 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
19271 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
19272 *
19273 * @example
19274 * See {@link ng.directive:ngClick ngClick}
19275 */
19276
19277/**
19278 * @ngdoc directive
19279 * @name ngCopy
19280 *
19281 * @description
19282 * Specify custom behavior on copy event.
19283 *
19284 * @element window, input, select, textarea, a
19285 * @priority 0
19286 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
19287 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
19288 *
19289 * @example
19290   <example>
19291     <file name="index.html">
19292      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
19293      copied: {{copied}}
19294     </file>
19295   </example>
19296 */
19297
19298/**
19299 * @ngdoc directive
19300 * @name ngCut
19301 *
19302 * @description
19303 * Specify custom behavior on cut event.
19304 *
19305 * @element window, input, select, textarea, a
19306 * @priority 0
19307 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
19308 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
19309 *
19310 * @example
19311   <example>
19312     <file name="index.html">
19313      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
19314      cut: {{cut}}
19315     </file>
19316   </example>
19317 */
19318
19319/**
19320 * @ngdoc directive
19321 * @name ngPaste
19322 *
19323 * @description
19324 * Specify custom behavior on paste event.
19325 *
19326 * @element window, input, select, textarea, a
19327 * @priority 0
19328 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19329 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19330 *
19331 * @example
19332   <example>
19333     <file name="index.html">
19334      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19335      pasted: {{paste}}
19336     </file>
19337   </example>
19338 */
19339
19340/**
19341 * @ngdoc directive
19342 * @name ngIf
19343 * @restrict A
19344 *
19345 * @description
19346 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19347 * {expression}. If the expression assigned to `ngIf` evaluates to a false
19348 * value then the element is removed from the DOM, otherwise a clone of the
19349 * element is reinserted into the DOM.
19350 *
19351 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19352 * element in the DOM rather than changing its visibility via the `display` css property.  A common
19353 * case when this difference is significant is when using css selectors that rely on an element's
19354 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
19354s.
19355 *
19356 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19357 * is created when the element is restored.  The scope created within `ngIf` inherits from
19358 * its parent scope using
19359 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
19360 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19361 * a javascript primitive defined in the parent scope. In this case any modifications made to the
19362 * variable within the child scope will override (hide) the value in the parent scope.
19363 *
19364 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19365 * is if an element's class attribute is directly modified after it's compiled, using something like
19366 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19367 * the added class will be lost because the original compiled state is used to regenerate the element.
19368 *
19369 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19370 * and `leave` effects.
19371 *
19372 * @animations
19373 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
19374 * leave - happens just before the ngIf contents are removed from the DOM
19375 *
19376 * @element ANY
19377 * @scope
19378 * @priority 600
19379 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19380 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19381 *     element is added to the DOM tree.
19382 *
19383 * @example
19384  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19385    <file name="index.html">
19386      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19387      Show when checked:
19388      <span ng-if="checked" class="animate-if">
19389        I'm removed when the checkbox is unchecked.
19390      </span>
19391    </file>
19392    <file name="animations.css">
19393      .animate-if {
19394        background:white;
19395        border:1px solid black;
19396        padding:10px;
19397      }
19398
19399      .animate-if.ng-enter, .animate-if.ng-leave {
19400        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19401        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19402      }
19403
19404      .animate-if.ng-enter,
19405      .animate-if.ng-leave.ng-leave-active {
19406        opacity:0;
19407      }
19408
19409      .animate-if.ng-leave,
19410      .animate-if.ng-enter.ng-enter-active {
19411        opacity:1;
19412      }
19413    </file>
19414  </example>
19415 */
19416var ngIfDirective = ['$animate', function($animate) {
19417  return {
19418    transclude: 'element',
19419    priority: 600,
19420    terminal: true,
19421    restrict: 'A',
19422    $$tlb: true,
19423    link: function ($scope, $element, $attr, ctrl, $transclude) {
19424        var block, childScope, previousElements;
19425        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19426
19427          if (toBoolean(value)) {
19428            if (!childScope) {
19429              childScope = $scope.$new();
19430              $transclude(childScope, function (clone) {
19431                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19432                // Note: We only need the first/last node of the cloned nodes.
19433                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19434                // by a directive with templateUrl when its template arrives.
19435                block = {
19436                  clone: clone
19437                };
19438                $animate.enter(clone, $element.parent(), $element);
19439              });
19440            }
19441          } else {
19442            if(previousElements) {
19443              previousElements.remove();
19444              previousElements = null;
19445            }
19446            if(childScope) {
19447              childScope.$destroy();
19448              childScope = null;
19449            }
19450            if(block) {
19451              previousElements = getBlockElements(block.clone);
19452              $animate.leave(previousElements, function() {
19453                previousElements = null;
19454              });
19455              block = null;
19456            }
19457          }
19458        });
19459    }
19460  };
19461}];
19462
19463/**
19464 * @ngdoc directive
19465 * @name ngInclude
19466 * @restrict ECA
19467 *
19468 * @description
19469 * Fetches, compiles and includes an external HTML fragment.
19470 *
19471 * By default, the template URL is restricted to the same domain and protocol as the
19472 * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19473 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19474 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19475 * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19476 * ng.$sce Strict Contextual Escaping}.
19477 *
19478 * In addition, the browser's
19479 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19480 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19481 * policy may further restrict whether the template is successfully loaded.
19482 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19483 * access on some browsers.
19484 *
19485 * @animations
19486 * enter - animation is used to bring new content into the browser.
19487 * leave - animation is used to animate existing content away.
19488 *
19489 * The enter and leave animation occur concurrently.
19490 *
19491 * @scope
19492 * @priority 400
19493 *
19494 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19495 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19496 * @param {string=} onload Expression to evaluate when a new partial is loaded.
19497 *
19498 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19499 *                  $anchorScroll} to scroll the viewport after the content is loaded.
19500 *
19501 *                  - If the attribute is not set, disable scrolling.
19502 *                  - If the attribute is set without value, enable scrolling.
19503 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19504 *
19505 * @example
19506  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19507    <file name="index.html">
19508     <div ng-controller="Ctrl">
19509       <select ng-model="template" ng-options="t.name for t in templates">
19510        <option value="">(blank)</option>
19511       </select>
19512       url of the template: <tt>{{template.url}}</tt>
19513       <hr/>
19514       <div class="slide-animate-container">
19515         <div class="slide-animate" ng-include="template.url"></div>
19516       </div>
19517     </div>
19518    </file>
19519    <file name="script.js">
19520      function Ctrl($scope) {
19521        $scope.templates =
19522          [ { name: 'template1.html', url: 'template1.html'},
19523            { name: 'template2.html', url: 'template2.html'} ];
19524        $scope.template = $scope.templates[0];
19525      }
19526     </file>
19527    <file name="template1.html">
19528      Content of template1.html
19529    </file>
19530    <file name="template2.html">
19531      Content of template2.html
19532    </file>
19533    <file name="animations.css">
19534      .slide-animate-container {
19535        position:relative;
19536        background:white;
19537        border:1px solid black;
19538        height:40px;
19539        overflow:hidden;
19540      }
19541
19542      .slide-animate {
19543        padding:10px;
19544      }
19545
19546      .slide-animate.ng-enter, .slide-animate.ng-leave {
19547        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19548        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19549
19550        position:absolute;
19551        top:0;
19552        left:0;
19553        right:0;
19554        bottom:0;
19555        display:block;
19556        padding:10px;
19557      }
19558
19559      .slide-animate.ng-enter {
19560        top:-50px;
19561      }
19562      .slide-animate.ng-enter.ng-enter-active {
19563        top:0;
19564      }
19565
19566      .slide-animate.ng-leave {
19567        top:0;
19568      }
19569      .slide-animate.ng-leave.ng-leave-active {
19570        top:50px;
19571      }
19572    </file>
19573    <file name="protractor.js" type="protractor">
19574      var templateSelect = element(by.model('template'));
19575      var includeElem = element(by.css('[ng-include]'));
19576
19577      it('should load template1.html', function() {
19578        expect(includeElem.getText()).toMatch(/Content of template1.html/);
19579      });
19580
19581      it('should load template2.html', function() {
19582        if (browser.params.browser == 'firefox') {
19583          // Firefox can't handle using selects
19584          // See https://github.com/angular/protractor/issues/480
19585          return;
19586        }
19587        templateSelect.click();
19588        templateSelect.element.all(by.css('option')).get(2).click();
19589        expect(includeElem.getText()).toMatch(/Content of template2.html/);
19590      });
19591
19592      it('should change to blank', function() {
19593        if (browser.params.browser == 'firefox') {
19594          // Firefox can't handle using selects
19595          return;
19596        }
19597        templateSelect.click();
19598        templateSelect.element.all(by.css('option')).get(0).click();
19599        expect(includeElem.isPresent()).toBe(false);
19600      });
19601    </file>
19602  </example>
19603 */
19604
19605
19606/**
19607 * @ngdoc event
19608 * @name ngInclude#$includeContentRequested
19609 * @eventType emit on the scope ngInclude was declared in
19610 * @description
19611 * Emitted every time the ngInclude content is requested.
19612 */
19613
19614
19615/**
19616 * @ngdoc event
19617 * @name ngInclude#$includeContentLoaded
19618 * @eventType emit on the current ngInclude scope
19619 * @description
19620 * Emitted every time the ngInclude content is reloaded.
19621 */
19622var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
19623                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
19624  return {
19625    restrict: 'ECA',
19626    priority: 400,
19627    terminal: true,
19628    transclude: 'element',
19629    controller: angular.noop,
19630    compile: function(element, attr) {
19631      var srcExp = attr.ngInclude || attr.src,
19632          onloadExp = attr.onload || '',
19633          autoScrollExp = attr.autoscroll;
19634
19635      return function(scope, $element, $attr, ctrl, $transclude) {
19636        var changeCounter = 0,
19637            currentScope,
19638            previousElement,
19639            currentElement;
19640
19641        var cleanupLastIncludeContent = function() {
19642          if(previousElement) {
19643            previousElement.remove();
19644            previousElement = null;
19645          }
19646          if(currentScope) {
19647            currentScope.$destroy();
19648            currentScope = null;
19649          }
19650          if(currentElement) {
19651            $animate.leave(currentElement, function() {
19652              previousElement = null;
19653            });
19654            previousElement = currentElement;
19655            currentElement = null;
19656          }
19657        };
19658
19659        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
19660          var afterAnimation = function() {
19661            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
19662              $anchorScroll();
19663            }
19664          };
19665          var thisChangeId = ++changeCounter;
19666
19667          if (src) {
19668            $http.get(src, {cache: $templateCache}).success(function(response) {
19669              if (thisChangeId !== changeCounter) return;
19670              var newScope = scope.$new();
19671              ctrl.template = response;
19672
19673              // Note: This will also link all children of ng-include that were contained in the original
19674              // html. If that content contains controllers, ... they could pollute/change the scope.
19675              // However, using ng-include on an element with additional content does not make sense...
19676              // Note: We can't remove them in the cloneAttchFn of $transclude as that
19677              // function is called before linking the content, which would apply child
19678              // directives to non existing elements.
19679              var clone = $transclude(newScope, function(clone) {
19680                cleanupLastIncludeContent();
19681                $animate.enter(clone, null, $element, afterAnimation);
19682              });
19683
19684              currentScope = newScope;
19685              currentElement = clone;
19686
19687              currentScope.$emit('$includeContentLoaded');
19688              scope.$eval(onloadExp);
19689            }).error(function() {
19690              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
19691            });
19692            scope.$emit('$includeContentRequested');
19693          } else {
19694            cleanupLastIncludeContent();
19695            ctrl.template = null;
19696          }
19697        });
19698      };
19699    }
19700  };
19701}];
19702
19703// This directive is called during the $transclude call of the first `ngInclude` directive.
19704// It will replace and compile the content of the element with the loaded template.
19705// We need this directive so that the element content is already filled when
19706// the link function of another directive on the same element as ngInclude
19707// is called.
19708var ngIncludeFillContentDirective = ['$compile',
19709  function($compile) {
19710    return {
19711      restrict: 'ECA',
19712      priority: -400,
19713      require: 'ngInclude',
19714      link: function(scope, $element, $attr, ctrl) {
19715        $element.html(ctrl.template);
19716        $compile($element.contents())(scope);
19717      }
19718    };
19719  }];
19720
19721/**
19722 * @ngdoc directive
19723 * @name ngInit
19724 * @restrict AC
19725 *
19726 * @description
19727 * The `ngInit` directive allows you to evaluate an expression in the
19728 * current scope.
19729 *
19730 * <div class="alert alert-error">
19731 * The only appropriate use of `ngInit` is for aliasing special properties of
19732 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
19733 * should use {@link guide/controller controllers} rather than `ngInit`
19734 * to initialize values on a scope.
19735 * </div>
19736 * <div class="alert alert-warning">
19737 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
19738 * sure you have parenthesis for correct precedence:
19739 * <pre class="prettyprint">
19740 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
19741 * </pre>
19742 * </div>
19743 *
19744 * @priority 450
19745 *
19746 * @element ANY
19747 * @param {expression} ngInit {@link guide/expression Expression} to eval.
19748 *
19749 * @example
19750   <example>
19751     <file name="index.html">
19752   <script>
19753     function Ctrl($scope) {
19754       $scope.list = [['a', 'b'], ['c', 'd']];
19755     }
19756   </script>
19757   <div ng-controller="Ctrl">
19758     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
19759       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
19760          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
19761       </div>
19762     </div>
19763   </div>
19764     </file>
19765     <file name="protractor.js" type="protractor">
19766       it('should alias index positions', function() {
19767         var elements = element.all(by.css('.example-init'));
19768         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
19769         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
19770         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
19771         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
19772       });
19773     </file>
19774   </example>
19775 */
19776var ngInitDirective = ngDirective({
19777  priority: 450,
19778  compile: function() {
19779    return {
19780      pre: function(scope, element, attrs) {
19781        scope.$eval(attrs.ngInit);
19782      }
19783    };
19784  }
19785});
19786
19787/**
19788 * @ngdoc directive
19789 * @name ngNonBindable
19790 * @restrict AC
19791 * @priority 1000
19792 *
19793 * @description
19794 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
19795 * DOM element. This is useful if the element contains what appears to be Angular directives and
19796 * bindings but which should be ignored by Angular. This could be the case if you have a site that
19797 * displays snippets of code, for instance.
19798 *
19799 * @element ANY
19800 *
19801 * @example
19802 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
19803 * but the one wrapped in `ngNonBindable` is left alone.
19804 *
19805 * @example
19806    <example>
19807      <file name="index.html">
19808        <div>Normal: {{1 + 2}}</div>
19809        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
19810      </file>
19811      <file name="protractor.js" type="protractor">
19812       it('should check ng-non-bindable', function() {
19813         expect(element(by.binding('1 + 2')).getText()).toContain('3');
19814         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
19815       });
19816      </file>
19817    </example>
19818 */
19819var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
19820
19821/**
19822 * @ngdoc directive
19823 * @name ngPluralize
19824 * @restrict EA
19825 *
19826 * @description
19827 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
19828 * These rules are bundled with angular.js, but can be overridden
19829 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
19830 * by specifying the mappings between
19831 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19832 * and the strings to be displayed.
19833 *
19834 * # Plural categories and explicit number rules
19835 * There are two
19836 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19837 * in Angular's default en-US locale: "one" and "other".
19838 *
19839 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
19840 * any number that is not 1), an explicit number rule can only match one number. For example, the
19841 * explicit number rule for "3" matches the number 3. There are examples of plural categories
19842 * and explicit number rules throughout the rest of this documentation.
19843 *
19844 * # Configuring ngPluralize
19845 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
19846 * You can also provide an optional attribute, `offset`.
19847 *
19848 * The value of the `count` attribute can be either a string or an {@link guide/expression
19849 * Angular expression}; these are evaluated on the current scope for its bound value.
19850 *
19851 * The `when` attribute specifies the mappings between plural categories and the actual
19852 * string to be displayed. The value of the attribute should be a JSON object.
19853 *
19854 * The following example shows how to configure ngPluralize:
19855 *
19856 * ```html
19857 * <ng-pluralize count="personCount"
19858                 when="{'0': 'Nobody is viewing.',
19859 *                      'one': '1 person is viewing.',
19860 *                      'other': '{} people are viewing.'}">
19861 * </ng-pluralize>
19862 *```
19863 *
19864 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
19865 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
19866 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
19867 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
19868 * show "a dozen people are viewing".
19869 *
19870 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
19871 * into pluralized strings. In the previous example, Angular will replace `{}` with
19872 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
19873 * for <span ng-non-bindable>{{numberExpression}}</span>.
19874 *
19875 * # Configuring ngPluralize with offset
19876 * The `offset` attribute allows further customization of pluralized text, which can result in
19877 * a better user experience. For example, instead of the message "4 people are viewing this document",
19878 * you might display "John, Kate and 2 others are viewing this document".
19879 * The offset attribute allows you to offset a number by any desired value.
19880 * Let's take a look at an example:
19881 *
19882 * ```html
19883 * <ng-pluralize count="personCount" offset=2
19884 *               when="{'0': 'Nobody is viewing.',
19885 *                      '1': '{{person1}} is viewing.',
19886 *                      '2': '{{person1}} and {{person2}} are viewing.',
19887 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
19888 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19889 * </ng-pluralize>
19890 * ```
19891 *
19892 * Notice that we are still using two plural categories(one, other), but we added
19893 * three explicit number rules 0, 1 and 2.
19894 * When one person, perhaps John, views the document, "John is viewing" will be shown.
19895 * When three people view the document, no explicit number rule is found, so
19896 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
19897 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
19898 * is shown.
19899 *
19900 * Note that when you specify offsets, you must provide explicit number rules for
19901 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
19902 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
19903 * plural categories "one" and "other".
19904 *
19905 * @param {string|expression} count The variable to be bound to.
19906 * @param {string} when The mapping between plural category to its corresponding strings.
19907 * @param {number=} offset Offset to deduct from the total number.
19908 *
19909 * @example
19910    <example>
19911      <file name="index.html">
19912        <script>
19913          function Ctrl($scope) {
19914            $scope.person1 = 'Igor';
19915            $scope.person2 = 'Misko';
19916            $scope.personCount = 1;
19917          }
19918        </script>
19919        <div ng-controller="Ctrl">
19920          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
19921          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
19922          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
19923
19924          <!--- Example with simple pluralization rules for en locale --->
19925          Without Offset:
19926          <ng-pluralize count="personCount"
19927                        when="{'0': 'Nobody is viewing.',
19928                               'one': '1 person is viewing.',
19929                               'other': '{} people are viewing.'}">
19930          </ng-pluralize><br>
19931
19932          <!--- Example with offset --->
19933          With Offset(2):
19934          <ng-pluralize count="personCount" offset=2
19935                        when="{'0': 'Nobody is viewing.',
19936                               '1': '{{person1}} is viewing.',
19937                               '2': '{{person1}} and {{person2}} are viewing.',
19938                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
19939                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19940          </ng-pluralize>
19941        </div>
19942      </file>
19943      <file name="protractor.js" type="protractor">
19944        it('should show correct pluralized string', function() {
19945          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
19946          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19947          var countInput = element(by.model('personCount'));
19948
19949          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
19950          expect(withOffset.getText()).toEqual('Igor is viewing.');
19951
19952          countInput.clear();
19953          countInput.sendKeys('0');
19954
19955          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
19956          expect(withOffset.getText()).toEqual('Nobody is viewing.');
19957
19958          countInput.clear();
19959          countInput.sendKeys('2');
19960
19961          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
19962          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
19963
19964          countInput.clear();
19965          countInput.sendKeys('3');
19966
19967          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
19968          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
19969
19970          countInput.clear();
19971          countInput.sendKeys('4');
19972
19973          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
19974          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
19975        });
19976        it('should show data-bound names', function() {
19977          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19978          var personCount = element(by.model('personCount'));
19979          var person1 = element(by.model('person1'));
19980          var person2 = element(by.model('person2'));
19981          personCount.clear();
19982          personCount.sendKeys('4');
19983          person1.clear();
19984          person1.sendKeys('Di');
19985          person2.clear();
19986          person2.sendKeys('Vojta');
19987          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
19988        });
19989      </file>
19990    </example>
19991 */
19992var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
19993  var BRACE = /{}/g;
19994  return {
19995    restrict: 'EA',
19996    link: function(scope, element, attr) {
19997      var numberExp = attr.count,
19998          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
19999          offset = attr.offset || 0,
20000          whens = scope.$eval(whenExp) || {},
20001          whensExpFns = {},
20002          startSymbol = $interpolate.startSymbol(),
20003          endSymbol = $interpolate.endSymbol(),
20004          isWhen = /^when(Minus)?(.+)$/;
20005
20006      forEach(attr, function(expression, attributeName) {
20007        if (isWhen.test(attributeName)) {
20008          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
20009            element.attr(attr.$attr[attributeName]);
20010        }
20011      });
20012      forEach(whens, function(expression, key) {
20013        whensExpFns[key] =
20014          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
20015            offset + endSymbol));
20016      });
20017
20018      scope.$watch(function ngPluralizeWatch() {
20019        var value = parseFloat(scope.$eval(numberExp));
20020
20021        if (!isNaN(value)) {
20022          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
20023          //check it against pluralization rules in $locale service
20024          if (!(value in whens)) value = $locale.pluralCat(value - offset);
20025           return whensExpFns[value](scope, element, true);
20026        } else {
20027          return '';
20028        }
20029      }, function ngPluralizeWatchAction(newVal) {
20030        element.text(newVal);
20031      });
20032    }
20033  };
20034}];
20035
20036/**
20037 * @ngdoc directive
20038 * @name ngRepeat
20039 *
20040 * @description
20041 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
20042 * instance gets its own scope, where the given loop variable is set to the current collection item,
20043 * and `$index` is set to the item index or key.
20044 *
20045 * Special properties are exposed on the local scope of each template instance, including:
20046 *
20047 * | Variable  | Type            | Details                                                                     |
20048 * |-----------|-----------------|-----------------------------------------------------------------------------|
20049 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
20050 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
20051 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
20052 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
20053 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
20054 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
20055 *
20056 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
20057 * This may be useful when, for instance, nesting ngRepeats.
20058 *
20059 * # Special repeat start and end points
20060 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
20061 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
20062 * 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)
20063 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
20064 *
20065 * The example below makes use of this feature:
20066 * ```html
20067 *   <header ng-repeat-start="item in items">
20068 *     Header {{ item }}
20069 *   </header>
20070 *   <div class="body">
20071 *     Body {{ item }}
20072 *   </div>
20073 *   <footer ng-repeat-end>
20074 *     Footer {{ item }}
20075 *   </footer>
20076 * ```
20077 *
20078 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
20079 * ```html
20080 *   <header>
20081 *     Header A
20082 *   </header>
20083 *   <div class="body">
20084 *     Body A
20085 *   </div>
20086 *   <footer>
20087 *     Footer A
20088 *   </footer>
20089 *   <header>
20090 *     Header B
20091 *   </header>
20092 *   <div class="body">
20093 *     Body B
20094 *   </div>
20095 *   <footer>
20096 *     Footer B
20097 *   </footer>
20098 * ```
20099 *
20100 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
20101 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
20102 *
20103 * @animations
20104 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
20105 *
20106 * **.leave** - when an item is removed from the list or when an item is filtered out
20107 *
20108 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
20109 *
20110 * @element ANY
20111 * @scope
20112 * @priority 1000
20113 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
20114 *   formats are currently supported:
20115 *
20116 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
20117 *     is a scope expression giving the collection to enumerate.
20118 *
20119 *     For example: `album in artist.albums`.
20120 *
20121 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
20122 *     and `expression` is the scope expression giving the collection to enumerate.
20123 *
20124 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
20125 *
20126 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
20127 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
20128 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
20129 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
20130 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
20131 *     before specifying a tracking expression.
20132 *
20133 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
20134 *     will be associated by item identity in the array.
20135 *
20136 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
20137 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
20138 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
20139 *     element in the same way in the DOM.
20140 *
20141 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
20142 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
20143 *     property is same.
20144 *
20145 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
20146 *     to items in conjunction with a tracking expression.
20147 *
20148 * @example
20149 * This example initializes the scope to a list of names and
20150 * then uses `ngRepeat` to display every person:
20151  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20152    <file name="index.html">
20153      <div ng-init="friends = [
20154        {name:'John', age:25, gender:'boy'},
20155        {name:'Jessie', age:30, gender:'girl'},
20156        {name:'Johanna', age:28, gender:'girl'},
20157        {name:'Joy', age:15, gender:'girl'},
20158        {name:'Mary', age:28, gender:'girl'},
20159        {name:'Peter', age:95, gender:'boy'},
20160        {name:'Sebastian', age:50, gender:'boy'},
20161        {name:'Erika', age:27, gender:'girl'},
20162        {name:'Patrick', age:40, gender:'boy'},
20163        {name:'Samantha', age:60, gender:'girl'}
20164      ]">
20165        I have {{friends.length}} friends. They are:
20166        <input type="search" ng-model="q" placeholder="filter friends..." />
20167        <ul class="example-animate-container">
20168          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
20169            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
20170          </li>
20171        </ul>
20172      </div>
20173    </file>
20174    <file name="animations.css">
20175      .example-animate-container {
20176        background:white;
20177        border:1px solid black;
20178        list-style:none;
20179        margin:0;
20180        padding:0 10px;
20181      }
20182
20183      .animate-repeat {
20184        line-height:40px;
20185        list-style:none;
20186        box-sizing:border-box;
20187      }
20188
20189      .animate-repeat.ng-move,
20190      .animate-repeat.ng-enter,
20191      .animate-repeat.ng-leave {
20192        -webkit-transition:all linear 0.5s;
20193        transition:all linear 0.5s;
20194      }
20195
20196      .animate-repeat.ng-leave.ng-leave-active,
20197      .animate-repeat.ng-move,
20198      .animate-repeat.ng-enter {
20199        opacity:0;
20200        max-height:0;
20201      }
20202
20203      .animate-repeat.ng-leave,
20204      .animate-repeat.ng-move.ng-move-active,
20205      .animate-repeat.ng-enter.ng-enter-active {
20206        opacity:1;
20207        max-height:40px;
20208      }
20209    </file>
20210    <file name="protractor.js" type="protractor">
20211      var friends = element.all(by.repeater('friend in friends'));
20212
20213      it('should render initial data set', function() {
20214        expect(friends.count()).toBe(10);
20215        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
20216        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
20217        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
20218        expect(element(by.binding('friends.length')).getText())
20219            .toMatch("I have 10 friends. They are:");
20220      });
20221
20222       it('should update repeater when filter predicate changes', function() {
20223         expect(friends.count()).toBe(10);
20224
20225         element(by.model('q')).sendKeys('ma');
20226
20227         expect(friends.count()).toBe(2);
20228         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
20229         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
20230       });
20231      </file>
20232    </example>
20233 */
20234var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20235  var NG_REMOVED = '$$NG_REMOVED';
20236  var ngRepeatMinErr = minErr('ngRepeat');
20237  return {
20238    transclude: 'element',
20239    priority: 1000,
20240    terminal: true,
20241    $$tlb: true,
20242    link: function($scope, $element, $attr, ctrl, $transclude){
20243        var expression = $attr.ngRepeat;
20244        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
20245          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
20246          lhs, rhs, valueIdentifier, keyIdentifier,
20247          hashFnLocals = {$id: hashKey};
20248
20249        if (!match) {
20250          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
20251            expression);
20252        }
20253
20254        lhs = match[1];
20255        rhs = match[2];
20256        trackByExp = match[3];
20257
20258        if (trackByExp) {
20259          trackByExpGetter = $parse(trackByExp);
20260          trackByIdExpFn = function(key, value, index) {
20261            // assign key, value, and $index to the locals so that they can be used in hash functions
20262            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
20263            hashFnLocals[valueIdentifier] = value;
20264            hashFnLocals.$index = index;
20265            return trackByExpGetter($scope, hashFnLocals);
20266          };
20267        } else {
20268          trackByIdArrayFn = function(key, value) {
20269            return hashKey(value);
20270          };
20271          trackByIdObjFn = function(key) {
20272            return key;
20273          };
20274        }
20275
20276        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
20277        if (!match) {
20278          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
20279                                                                    lhs);
20280        }
20281        valueIdentifier = match[3] || match[1];
20282        keyIdentifier = match[2];
20283
20284        // Store a list of elements from previous run. This is a hash where key is the item from the
20285        // iterator, and the value is objects with following properties.
20286        //   - scope: bound scope
20287        //   - element: previous element.
20288        //   - index: position
20289        var lastBlockMap = {};
20290
20291        //watch props
20292        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
20293          var index, length,
20294              previousNode = $element[0],     // current position of the node
20295              nextNode,
20296              // Same as lastBlockMap but it has the current state. It will become the
20297              // lastBlockMap on the next iteration.
20298              nextBlockMap = {},
20299              arrayLength,
20300              childScope,
20301              key, value, // key/value of iteration
20302              trackById,
20303              trackByIdFn,
20304              collectionKeys,
20305              block,       // last object information {scope, element, id}
20306              nextBlockOrder = [],
20307              elementsToRemove;
20308
20309
20310          if (isArrayLike(collection)) {
20311            collectionKeys = collection;
20312            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
20313          } else {
20314            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
20315            // if object, extract keys, sort them and use to determine order of iteration over obj props
20316            collectionKeys = [];
20317            for (key in collection) {
20318              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
20319                collectionKeys.push(key);
20320              }
20321            }
20322            collectionKeys.sort();
20323          }
20324
20325          arrayLength = collectionKeys.length;
20326
20327          // locate existing items
20328          length = nextBlockOrder.length = collectionKeys.length;
20329          for(index = 0; index < length; index++) {
20330           key = (collection === collectionKeys) ? index : collectionKeys[index];
20331           value = collection[key];
20332           trackById = trackByIdFn(key, value, index);
20333           assertNotHasOwnProperty(trackById, '`track by` id');
20334           if(lastBlockMap.hasOwnProperty(trackById)) {
20335             block = lastBlockMap[trackById];
20336             delete lastBlockMap[trackById];
20337             nextBlockMap[trackById] = block;
20338             nextBlockOrder[index] = block;
20339           } else if (nextBlockMap.hasOwnProperty(trackById)) {
20340             // restore lastBlockMap
20341             forEach(nextBlockOrder, function(block) {
20342               if (block && block.scope) lastBlockMap[block.id] = block;
20343             });
20344             // This is a duplicate and we need to throw an error
20345             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
20346                                                                                                                                                    expression,       trackById);
20347           } else {
20348             // new never before seen block
20349             nextBlockOrder[index] = { id: trackById };
20350             nextBlockMap[trackById] = false;
20351           }
20352         }
20353
20354          // remove existing items
20355          for (key in lastBlockMap) {
20356            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20357            if (lastBlockMap.hasOwnProperty(key)) {
20358              block = lastBlockMap[key];
20359              elementsToRemove = getBlockElements(block.clone);
20360              $animate.leave(elementsToRemove);
20361              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
20362              block.scope.$destroy();
20363            }
20364          }
20365
20366          // we are not using forEach for perf reasons (trying to avoid #call)
20367          for (index = 0, length = collectionKeys.length; index < length; index++) {
20368            key = (collection === collectionKeys) ? index : collectionKeys[index];
20369            value = collection[key];
20370            block = nextBlockOrder[index];
20371            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20372
20373            if (block.scope) {
20374              // if we have already seen this object, then we need to reuse the
20375              // associated scope/element
20376              childScope = block.scope;
20377
20378              nextNode = previousNode;
20379              do {
20380                nextNode = nextNode.nextSibling;
20381              } while(nextNode && nextNode[NG_REMOVED]);
20382
20383              if (getBlockStart(block) != nextNode) {
20384                // existing item which got moved
20385                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20386              }
20387              previousNode = getBlockEnd(block);
20388            } else {
20389              // new item which we don't know about
20390              childScope = $scope.$new();
20391            }
20392
20393            childScope[valueIdentifier] = value;
20394            if (keyIdentifier) childScope[keyIdentifier] = key;
20395            childScope.$index = index;
20396            childScope.$first = (index === 0);
20397            childScope.$last = (index === (arrayLength - 1));
20398            childScope.$middle = !(childScope.$first || childScope.$last);
20399            // jshint bitwise: false
20400            childScope.$odd = !(childScope.$even = (index&1) === 0);
20401            // jshint bitwise: true
20402
20403            if (!block.scope) {
20404              $transclude(childScope, function(clone) {
20405                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20406                $animate.enter(clone, null, jqLite(previousNode));
20407                previousNode = clone;
20408                block.scope = childScope;
20409                // Note: We only need the first/last node of the cloned nodes.
20410                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20411                // by a directive with templateUrl when its template arrives.
20412                block.clone = clone;
20413                nextBlockMap[block.id] = block;
20414              });
20415            }
20416          }
20417          lastBlockMap = nextBlockMap;
20418        });
20419    }
20420  };
20421
20422  function getBlockStart(block) {
20423    return block.clone[0];
20424  }
20425
20426  function getBlockEnd(block) {
20427    return block.clone[block.clone.length - 1];
20428  }
20429}];
20430
20431/**
20432 * @ngdoc directive
20433 * @name ngShow
20434 *
20435 * @description
20436 * The `ngShow` directive shows or hides the given HTML element based on the expression
20437 * provided to the ngShow attribute. The element is shown or hidden by removing or adding
20438 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20439 * in AngularJS and sets the display style to none (using an !important flag).
20440 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20441 *
20442 * ```html
20443 * <!-- when $scope.myValue is truthy (element is visible) -->
20444 * <div ng-show="myValue"></div>
20445 *
20446 * <!-- when $scope.myValue is falsy (element is hidden) -->
20447 * <div ng-show="myValue" class="ng-hide"></div>
20448 * ```
20449 *
20450 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
20451 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20452 * from the element causing the element not to appear hidden.
20453 *
20454 * <div class="alert alert-warning">
20455 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20456 * "f" / "0" / "false" / "no" / "n" / "[]"
20457 * </div>
20458 *
20459 * ## Why is !important used?
20460 *
20461 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20462 * can be easily overridden by heavier selectors. For example, something as simple
20463 * as changing the display style on a HTML list item would make hidden elements appear visible.
20464 * This also becomes a bigger issue when dealing with CSS frameworks.
20465 *
20466 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20467 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20468 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20469 *
20470 * ### Overriding .ng-hide
20471 *
20472 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20473 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20474 * class in CSS:
20475 *
20476 * ```css
20477 * .ng-hide {
20478 *   //this is just another form of hiding an element
20479 *   display:block!important;
20480 *   position:absolute;
20481 *   top:-9999px;
20482 *   left:-9999px;
20483 * }
20484 * ```
20485 *
20486 * By default you don't need to override in CSS anything and the animations will work around the display style.
20487 *
20488 * ## A note about animations with ngShow
20489 *
20490 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20491 * is true and false. This system works like the animation system present with ngClass except that
20492 * you must also include the !important flag to override the display property
20493 * so that you can perform an animation when the element is hidden during the time of the animation.
20494 *
20495 * ```css
20496 * //
20497 * //a working example can be found at the bottom of this page
20498 * //
20499 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20500 *   transition:0.5s linear all;
20501 * }
20502 *
20503 * .my-element.ng-hide-add { ... }
20504 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20505 * .my-element.ng-hide-remove { ... }
20506 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20507 * ```
20508 *
20509 * 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
20510 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20511 *
20512 * @animations
20513 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20514 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
20515 *
20516 * @element ANY
20517 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20518 *     then the element is shown or hidden respectively.
20519 *
20520 * @example
20521  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20522    <file name="index.html">
20523      Click me: <input type="checkbox" ng-model="checked"><br/>
20524      <div>
20525        Show:
20526        <div class="check-element animate-show" ng-show="checked">
20527          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20528        </div>
20529      </div>
20530      <div>
20531        Hide:
20532        <div class="check-element animate-show" ng-hide="checked">
20533          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20534        </div>
20535      </div>
20536    </file>
20537    <file name="glyphicons.css">
20538      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20539    </file>
20540    <file name="animations.css">
20541      .animate-show {
20542        -webkit-transition:all linear 0.5s;
20543        transition:all linear 0.5s;
20544        line-height:20px;
20545        opacity:1;
20546        padding:10px;
20547        border:1px solid black;
20548        background:white;
20549      }
20550
20551      .animate-show.ng-hide {
20552        line-height:0;
20553        opacity:0;
20554        padding:0 10px;
20555      }
20556
20557      .check-element {
20558        padding:10px;
20559        border:1px solid black;
20560        background:white;
20561      }
20562    </file>
20563    <file name="protractor.js" type="protractor">
20564      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20565      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20566
20567      it('should check ng-show / ng-hide', function() {
20568        expect(thumbsUp.isDisplayed()).toBeFalsy();
20569        expect(thumbsDown.isDisplayed()).toBeTruthy();
20570
20571        element(by.model('checked')).click();
20572
20573        expect(thumbsUp.isDisplayed()).toBeTruthy();
20574        expect(thumbsDown.isDisplayed()).toBeFalsy();
20575      });
20576    </file>
20577  </example>
20578 */
20579var ngShowDirective = ['$animate', function($animate) {
20580  return function(scope, element, attr) {
20581    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
20582      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20583    });
20584  };
20585}];
20586
20587
20588/**
20589 * @ngdoc directive
20590 * @name ngHide
20591 *
20592 * @description
20593 * The `ngHide` directive shows or hides the given HTML element based on the expression
20594 * provided to the ngHide attribute. The element is shown or hidden by removing or adding
20595 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20596 * in AngularJS and sets the display style to none (using an !important flag).
20597 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20598 *
20599 * ```html
20600 * <!-- when $scope.myValue is truthy (element is hidden) -->
20601 * <div ng-hide="myValue" class="ng-hide"></div>
20602 *
20603 * <!-- when $scope.myValue is falsy (element is visible) -->
20604 * <div ng-hide="myValue"></div>
20605 * ```
20606 *
20607 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20608 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20609 * from the element causing the element not to appear hidden.
20610 *
20611 * <div class="alert alert-warning">
20612 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20613 * "f" / "0" / "false" / "no" / "n" / "[]"
20614 * </div>
20615 *
20616 * ## Why is !important used?
20617 *
20618 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20619 * can be easily overridden by heavier selectors. For example, something as simple
20620 * as changing the display style on a HTML list item would make hidden elements appear visible.
20621 * This also becomes a bigger issue when dealing with CSS frameworks.
20622 *
20623 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20624 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20625 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20626 *
20627 * ### Overriding .ng-hide
20628 *
20629 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20630 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20631 * class in CSS:
20632 *
20633 * ```css
20634 * .ng-hide {
20635 *   //this is just another form of hiding an element
20636 *   display:block!important;
20637 *   position:absolute;
20638 *   top:-9999px;
20639 *   left:-9999px;
20640 * }
20641 * ```
20642 *
20643 * By default you don't need to override in CSS anything and the animations will work around the display style.
20644 *
20645 * ## A note about animations with ngHide
20646 *
20647 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20648 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
20649 * CSS class is added and removed for you instead of your own CSS class.
20650 *
20651 * ```css
20652 * //
20653 * //a working example can be found at the bottom of this page
20654 * //
20655 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20656 *   transition:0.5s linear all;
20657 * }
20658 *
20659 * .my-element.ng-hide-add { ... }
20660 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20661 * .my-element.ng-hide-remove { ... }
20662 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20663 * ```
20664 *
20665 * 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
20666 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20667 *
20668 * @animations
20669 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20670 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
20671 *
20672 * @element ANY
20673 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
20674 *     the element is shown or hidden respectively.
20675 *
20676 * @example
20677  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20678    <file name="index.html">
20679      Click me: <input type="checkbox" ng-model="checked"><br/>
20680      <div>
20681        Show:
20682        <div class="check-element animate-hide" ng-show="checked">
20683          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20684        </div>
20685      </div>
20686      <div>
20687        Hide:
20688        <div class="check-element animate-hide" ng-hide="checked">
20689          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20690        </div>
20691      </div>
20692    </file>
20693    <file name="glyphicons.css">
20694      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20695    </file>
20696    <file name="animations.css">
20697      .animate-hide {
20698        -webkit-transition:all linear 0.5s;
20699        transition:all linear 0.5s;
20700        line-height:20px;
20701        opacity:1;
20702        padding:10px;
20703        border:1px solid black;
20704        background:white;
20705      }
20706
20707      .animate-hide.ng-hide {
20708        line-height:0;
20709        opacity:0;
20710        padding:0 10px;
20711      }
20712
20713      .check-element {
20714        padding:10px;
20715        border:1px solid black;
20716        background:white;
20717      }
20718    </file>
20719    <file name="protractor.js" type="protractor">
20720      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20721      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20722
20723      it('should check ng-show / ng-hide', function() {
20724        expect(thumbsUp.isDisplayed()).toBeFalsy();
20725        expect(thumbsDown.isDisplayed()).toBeTruthy();
20726
20727        element(by.model('checked')).click();
20728
20729        expect(thumbsUp.isDisplayed()).toBeTruthy();
20730        expect(thumbsDown.isDisplayed()).toBeFalsy();
20731      });
20732    </file>
20733  </example>
20734 */
20735var ngHideDirective = ['$animate', function($animate) {
20736  return function(scope, element, attr) {
20737    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
20738      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
20739    });
20740  };
20741}];
20742
20743/**
20744 * @ngdoc directive
20745 * @name ngStyle
20746 * @restrict AC
20747 *
20748 * @description
20749 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20750 *
20751 * @element ANY
20752 * @param {expression} ngStyle
20753 *
20754 * {@link guide/expression Expression} which evals to an
20755 * object whose keys are CSS style names and values are corresponding values for those CSS
20756 * keys.
20757 *
20758 * Since some CSS style names are not valid keys for an object, they must be quoted.
20759 * See the 'background-color' style in the example below.
20760 *
20761 * @example
20762   <example>
20763     <file name="index.html">
20764        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
20765        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
20766        <input type="button" value="clear" ng-click="myStyle={}">
20767        <br/>
20768        <span ng-style="myStyle">Sample Text</span>
20769        <pre>myStyle={{myStyle}}</pre>
20770     </file>
20771     <file name="style.css">
20772       span {
20773         color: black;
20774       }
20775     </file>
20776     <file name="protractor.js" type="protractor">
20777       var colorSpan = element(by.css('span'));
20778
20779       it('should check ng-style', function() {
20780         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20781         element(by.css('input[value=\'set color\']')).click();
20782         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
20783         element(by.css('input[value=clear]')).click();
20784         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20785       });
20786     </file>
20787   </example>
20788 */
20789var ngStyleDirective = ngDirective(function(scope, element, attr) {
20790  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
20791    if (oldStyles && (newStyles !== oldStyles)) {
20792      forEach(oldStyles, function(val, style) { element.css(style, '');});
20793    }
20794    if (newStyles) element.css(newStyles);
20795  }, true);
20796});
20797
20798/**
20799 * @ngdoc directive
20800 * @name ngSwitch
20801 * @restrict EA
20802 *
20803 * @description
20804 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
20805 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
20806 * as specified in the template.
20807 *
20808 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
20809 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
20810 * matches the value obtained from the evaluated expression. In other words, you define a container element
20811 * (where you place the directive), place an expression on the **`on="..."` attribute**
20812 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
20813 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
20814 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
20815 * attribute is displayed.
20816 *
20817 * <div class="alert alert-info">
20818 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
20819 * as literal string values to match against.
20820 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
20820omeVal"` not against the
20821 * value of the expression `$scope.someVal`.
20822 * </div>
20823
20824 * @animations
20825 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
20826 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
20827 *
20828 * @usage
20829 *
20830 * ```
20831 * <ANY ng-switch="expression">
20832 *   <ANY ng-switch-when="matchValue1">...</ANY>
20833 *   <ANY ng-switch-when="matchValue2">...</ANY>
20834 *   <ANY ng-switch-default>...</ANY>
20835 * </ANY>
20836 * ```
20837 *
20838 *
20839 * @scope
20840 * @priority 800
20841 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
20842 * On child elements add:
20843 *
20844 * * `ngSwitchWhen`: the case statement to match against. If match then this
20845 *   case will be displayed. If the same match appears multiple times, all the
20846 *   elements will be displayed.
20847 * * `ngSwitchDefault`: the default case when no other case match. If there
20848 *   are multiple default cases, all of them will be displayed when no other
20849 *   case match.
20850 *
20851 *
20852 * @example
20853  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20854    <file name="index.html">
20855      <div ng-controller="Ctrl">
20856        <select ng-model="selection" ng-options="item for item in items">
20857        </select>
20858        <tt>selection={{selection}}</tt>
20859        <hr/>
20860        <div class="animate-switch-container"
20861          ng-switch on="selection">
20862            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
20863            <div class="animate-switch" ng-switch-when="home">Home Span</div>
20864            <div class="animate-switch" ng-switch-default>default</div>
20865        </div>
20866      </div>
20867    </file>
20868    <file name="script.js">
20869      function Ctrl($scope) {
20870        $scope.items = ['settings', 'home', 'other'];
20871        $scope.selection = $scope.items[0];
20872      }
20873    </file>
20874    <file name="animations.css">
20875      .animate-switch-container {
20876        position:relative;
20877        background:white;
20878        border:1px solid black;
20879        height:40px;
20880        overflow:hidden;
20881      }
20882
20883      .animate-switch {
20884        padding:10px;
20885      }
20886
20887      .animate-switch.ng-animate {
20888        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20889        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20890
20891        position:absolute;
20892        top:0;
20893        left:0;
20894        right:0;
20895        bottom:0;
20896      }
20897
20898      .animate-switch.ng-leave.ng-leave-active,
20899      .animate-switch.ng-enter {
20900        top:-50px;
20901      }
20902      .animate-switch.ng-leave,
20903      .animate-switch.ng-enter.ng-enter-active {
20904        top:0;
20905      }
20906    </file>
20907    <file name="protractor.js" type="protractor">
20908      var switchElem = element(by.css('[ng-switch]'));
20909      var select = element(by.model('selection'));
20910
20911      it('should start in settings', function() {
20912        expect(switchElem.getText()).toMatch(/Settings Div/);
20913      });
20914      it('should change to home', function() {
20915        select.element.all(by.css('option')).get(1).click();
20916        expect(switchElem.getText()).toMatch(/Home Span/);
20917      });
20918      it('should select default', function() {
20919        select.element.all(by.css('option')).get(2).click();
20920        expect(switchElem.getText()).toMatch(/default/);
20921      });
20922    </file>
20923  </example>
20924 */
20925var ngSwitchDirective = ['$animate', function($animate) {
20926  return {
20927    restrict: 'EA',
20928    require: 'ngSwitch',
20929
20930    // asks for $scope to fool the BC controller module
20931    controller: ['$scope', function ngSwitchController() {
20932     this.cases = {};
20933    }],
20934    link: function(scope, element, attr, ngSwitchController) {
20935      var watchExpr = attr.ngSwitch || attr.on,
20936          selectedTranscludes = [],
20937          selectedElements = [],
20938          previousElements = [],
20939          selectedScopes = [];
20940
20941      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
20942        var i, ii;
20943        for (i = 0, ii = previousElements.length; i < ii; ++i) {
20944          previousElements[i].remove();
20945        }
20946        previousElements.length = 0;
20947
20948        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
20949          var selected = selectedElements[i];
20950          selectedScopes[i].$destroy();
20951          previousElements[i] = selected;
20952          $animate.leave(selected, function() {
20953            previousElements.splice(i, 1);
20954          });
20955        }
20956
20957        selectedElements.length = 0;
20958        selectedScopes.length = 0;
20959
20960        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
20961          scope.$eval(attr.change);
20962          forEach(selectedTranscludes, function(selectedTransclude) {
20963            var selectedScope = scope.$new();
20964            selectedScopes.push(selectedScope);
20965            selectedTransclude.transclude(selectedScope, function(caseElement) {
20966              var anchor = selectedTransclude.element;
20967
20968              selectedElements.push(caseElement);
20969              $animate.enter(caseElement, anchor.parent(), anchor);
20970            });
20971          });
20972        }
20973      });
20974    }
20975  };
20976}];
20977
20978var ngSwitchWhenDirective = ngDirective({
20979  transclude: 'element',
20980  priority: 800,
20981  require: '^ngSwitch',
20982  link: function(scope, element, attrs, ctrl, $transclude) {
20983    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
20984    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
20985  }
20986});
20987
20988var ngSwitchDefaultDirective = ngDirective({
20989  transclude: 'element',
20990  priority: 800,
20991  require: '^ngSwitch',
20992  link: function(scope, element, attr, ctrl, $transclude) {
20993    ctrl.cases['?'] = (ctrl.cases['?'] || []);
20994    ctrl.cases['?'].push({ transclude: $transclude, element: element });
20995   }
20996});
20997
20998/**
20999 * @ngdoc directive
21000 * @name ngTransclude
21001 * @restrict AC
21002 *
21003 * @description
21004 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
21005 *
21006 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
21007 *
21008 * @element ANY
21009 *
21010 * @example
21011   <example module="transclude">
21012     <file name="index.html">
21013       <script>
21014         function Ctrl($scope) {
21015           $scope.title = 'Lorem Ipsum';
21016           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
21017         }
21018
21019         angular.module('transclude', [])
21020          .directive('pane', function(){
21021             return {
21022               restrict: 'E',
21023               transclude: true,
21024               scope: { title:'@' },
21025               template: '<div style="border: 1px solid black;">' +
21026                           '<div style="background-color: gray">{{title}}</div>' +
21027                           '<div ng-transclude></div>' +
21028                         '</div>'
21029             };
21030         });
21031       </script>
21032       <div ng-controller="Ctrl">
21033         <input ng-model="title"><br>
21034         <textarea ng-model="text"></textarea> <br/>
21035         <pane title="{{title}}">{{text}}</pane>
21036       </div>
21037     </file>
21038     <file name="protractor.js" type="protractor">
21039        it('should have transcluded', function() {
21040          var titleElement = element(by.model('title'));
21041          titleElement.clear();
21042          titleElement.sendKeys('TITLE');
21043          var textElement = element(by.model('text'));
21044          textElement.clear();
21045          textElement.sendKeys('TEXT');
21046          expect(element(by.binding('title')).getText()).toEqual('TITLE');
21047          expect(element(by.binding('text')).getText()).toEqual('TEXT');
21048        });
21049     </file>
21050   </example>
21051 *
21052 */
21053var ngTranscludeDirective = ngDirective({
21054  link: function($scope, $element, $attrs, controller, $transclude) {
21055    if (!$transclude) {
21056      throw minErr('ngTransclude')('orphan',
21057       'Illegal use of ngTransclude directive in the template! ' +
21058       'No parent directive that requires a transclusion found. ' +
21059       'Element: {0}',
21060       startingTag($element));
21061    }
21062
21063    $transclude(function(clone) {
21064      $element.empty();
21065      $element.append(clone);
21066    });
21067  }
21068});
21069
21070/**
21071 * @ngdoc directive
21072 * @name script
21073 * @restrict E
21074 *
21075 * @description
21076 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
21077 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
21078 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
21079 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
21080 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
21081 *
21082 * @param {string} type Must be set to `'text/ng-template'`.
21083 * @param {string} id Cache name of the template.
21084 *
21085 * @example
21086  <example>
21087    <file name="index.html">
21088      <script type="text/ng-template" id="/tpl.html">
21089        Content of the template.
21090      </script>
21091
21092      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
21093      <div id="tpl-content" ng-include src="currentTpl"></div>
21094    </file>
21095    <file name="protractor.js" type="protractor">
21096      it('should load template defined inside script tag', function() {
21097        element(by.css('#tpl-link')).click();
21098        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
21099      });
21100    </file>
21101  </example>
21102 */
21103var scriptDirective = ['$templateCache', function($templateCache) {
21104  return {
21105    restrict: 'E',
21106    terminal: true,
21107    compile: function(element, attr) {
21108      if (attr.type == 'text/ng-template') {
21109        var templateUrl = attr.id,
21110            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
21111            text = element[0].text;
21112
21113        $templateCache.put(templateUrl, text);
21114      }
21115    }
21116  };
21117}];
21118
21119var ngOptionsMinErr = minErr('ngOptions');
21120/**
21121 * @ngdoc directive
21122 * @name select
21123 * @restrict E
21124 *
21125 * @description
21126 * HTML `SELECT` element with angular data-binding.
21127 *
21128 * # `ngOptions`
21129 *
21130 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
21131 * elements for the `<select>` element using the array or object obtained by evaluating the
21132 * `ngOptions` comprehension_expression.
21133 *
21134 * When an item in the `<select>` menu is selected, the array element or object property
21135 * represented by the selected option will be bound to the model identified by the `ngModel`
21136 * directive.
21137 *
21138 * <div class="alert alert-warning">
21139 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
21140 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
21141 * </div>
21142 *
21143 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
21144 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
21145 * option. See example below for demonstration.
21146 *
21147 * <div class="alert alert-warning">
21148 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
21149 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
21150 * `select` model to be bound to a non-string value. This is because an option element can only
21151 * be bound to string values at present.
21152 * </div>
21153 *
21154 * @param {string} ngModel Assignable angular expression to data-bind to.
21155 * @param {string=} name Property name of the form under which the control is published.
21156 * @param {string=} required The control is considered valid only if value is entered.
21157 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21158 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21159 *    `required` when you want to data-bind to the `required` attribute.
21160 * @param {comprehension_expression=} ngOptions in one of the following forms:
21161 *
21162 *   * for array data sources:
21163 *     * `label` **`for`** `value` **`in`** `array`
21164 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
21165 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
21166 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
21167 *   * for object data sources:
21168 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21169 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21170 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
21171 *     * `select` **`as`** `label` **`group by`** `group`
21172 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
21173 *
21174 * Where:
21175 *
21176 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
21177 *   * `value`: local variable which will refer to each item in the `array` or each property value
21178 *      of `object` during iteration.
21179 *   * `key`: local variable which will refer to a property name in `object` during iteration.
21180 *   * `label`: The result of this expression will be the label for `<option>` element. The
21181 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
21182 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
21183 *      element. If not specified, `select` expression will default to `value`.
21184 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
21185 *      DOM element.
21186 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
21187 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
21188 *     `value` variable (e.g. `value.propertyName`).
21189 *
21190 * @example
21191    <example>
21192      <file name="index.html">
21193        <script>
21194        function MyCntrl($scope) {
21195          $scope.colors = [
21196            {name:'black', shade:'dark'},
21197            {name:'white', shade:'light'},
21198            {name:'red', shade:'dark'},
21199            {name:'blue', shade:'dark'},
21200            {name:'yellow', shade:'light'}
21201          ];
21202          $scope.myColor = $scope.colors[2]; // red
21203        }
21204        </script>
21205        <div ng-controller="MyCntrl">
21206          <ul>
21207            <li ng-repeat="color in colors">
21208              Name: <input ng-model="color.name">
21209              [<a href ng-click="colors.splice($index, 1)">X</a>]
21210            </li>
21211            <li>
21212              [<a href ng-click="colors.push({})">add</a>]
21213            </li>
21214          </ul>
21215          <hr/>
21216          Color (null not allowed):
21217          <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
21218
21219          Color (null allowed):
21220          <span  class="nullable">
21221            <select ng-model="myColor" ng-options="color.name for color in colors">
21222              <option value="">-- choose color --</option>
21223            </select>
21224          </span><br/>
21225
21226          Color grouped by shade:
21227          <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
21228          </select><br/>
21229
21230
21231          Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
21232          <hr/>
21233          Currently selected: {{ {selected_color:myColor}  }}
21234          <div style="border:solid 1px black; height:20px"
21235               ng-style="{'background-color':myColor.name}">
21236          </div>
21237        </div>
21238      </file>
21239      <file name="protractor.js" type="protractor">
21240         it('should check ng-options', function() {
21241           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
21242           element.all(by.select('myColor')).first().click();
21243           element.all(by.css('select[ng-model="myColor"] option')).first().click();
21244           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
21245           element(by.css('.nullable select[ng-model="myColor"]')).click();
21246           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
21247           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
21248         });
21249      </file>
21250    </example>
21251 */
21252
21253var ngOptionsDirective = valueFn({ terminal: true });
21254// jshint maxlen: false
21255var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
21256                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
21257  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]+?))?$/,
21258      nullModelCtrl = {$setViewValue: noop};
21259// jshint maxlen: 100
21260
21261  return {
21262    restrict: 'E',
21263    require: ['select', '?ngModel'],
21264    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
21265      var self = this,
21266          optionsMap = {},
21267          ngModelCtrl = nullModelCtrl,
21268          nullOption,
21269          unknownOption;
21270
21271
21272      self.databound = $attrs.ngModel;
21273
21274
21275      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
21276        ngModelCtrl = ngModelCtrl_;
21277        nullOption = nullOption_;
21278        unknownOption = unknownOption_;
21279      };
21280
21281
21282      self.addOption = function(value) {
21283        assertNotHasOwnProperty(value, '"option value"');
21284        optionsMap[value] = true;
21285
21286        if (ngModelCtrl.$viewValue == value) {
21287          $element.val(value);
21288          if (unknownOption.parent()) unknownOption.remove();
21289        }
21290      };
21291
21292
21293      self.removeOption = function(value) {
21294        if (this.hasOption(value)) {
21295          delete optionsMap[value];
21296          if (ngModelCtrl.$viewValue == value) {
21297            this.renderUnknownOption(value);
21298          }
21299        }
21300      };
21301
21302
21303      self.renderUnknownOption = function(val) {
21304        var unknownVal = '? ' + hashKey(val) + ' ?';
21305        unknownOption.val(unknownVal);
21306        $element.prepend(unknownOption);
21307        $element.val(unknownVal);
21308        unknownOption.prop('selected', true); // needed for IE
21309      };
21310
21311
21312      self.hasOption = function(value) {
21313        return optionsMap.hasOwnProperty(value);
21314      };
21315
21316      $scope.$on('$destroy', function() {
21317        // disable unknown option so that we don't do work when the whole select is being destroyed
21318        self.renderUnknownOption = noop;
21319      });
21320    }],
21321
21322    link: function(scope, element, attr, ctrls) {
21323      // if ngModel is not defined, we don't need to do anything
21324      if (!ctrls[1]) return;
21325
21326      var selectCtrl = ctrls[0],
21327          ngModelCtrl = ctrls[1],
21328          multiple = attr.multiple,
21329          optionsExp = attr.ngOptions,
21330          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21331          emptyOption,
21332          // we can't just jqLite('<option>') since jqLite is not smart enough
21333          // to create it in <select> and IE barfs otherwise.
21334          optionTemplate = jqLite(document.createElement('option')),
21335          optGroupTemplate =jqLite(document.createElement('optgroup')),
21336          unknownOption = optionTemplate.clone();
21337
21338      // find "null" option
21339      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21340        if (children[i].value === '') {
21341          emptyOption = nullOption = children.eq(i);
21342          break;
21343        }
21344      }
21345
21346      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21347
21348      // required validator
21349      if (multiple) {
21350        ngModelCtrl.$isEmpty = function(value) {
21351          return !value || value.length === 0;
21352        };
21353      }
21354
21355      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21356      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21357      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21358
21359
21360      ////////////////////////////
21361
21362
21363
21364      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21365        ngModelCtrl.$render = function() {
21366          var viewValue = ngModelCtrl.$viewValue;
21367
21368          if (selectCtrl.hasOption(viewValue)) {
21369            if (unknownOption.parent()) unknownOption.remove();
21370            selectElement.val(viewValue);
21371            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21372          } else {
21373            if (isUndefined(viewValue) && emptyOption) {
21374              selectElement.val('');
21375            } else {
21376              selectCtrl.renderUnknownOption(viewValue);
21377            }
21378          }
21379        };
21380
21381        selectElement.on('change', function() {
21382          scope.$apply(function() {
21383            if (unknownOption.parent()) unknownOption.remove();
21384            ngModelCtrl.$setViewValue(selectElement.val());
21385          });
21386        });
21387      }
21388
21389      function setupAsMultiple(scope, selectElement, ctrl) {
21390        var lastView;
21391        ctrl.$render = function() {
21392          var items = new HashMap(ctrl.$viewValue);
21393          forEach(selectElement.find('option'), function(option) {
21394            option.selected = isDefined(items.get(option.value));
21395          });
21396        };
21397
21398        // we have to do it on each watch since ngModel watches reference, but
21399        // we need to work of an array, so we need to see if anything was inserted/removed
21400        scope.$watch(function selectMultipleWatch() {
21401          if (!equals(lastView, ctrl.$viewValue)) {
21402            lastView = shallowCopy(ctrl.$viewValue);
21403            ctrl.$render();
21404          }
21405        });
21406
21407        selectElement.on('change', function() {
21408          scope.$apply(function() {
21409            var array = [];
21410            forEach(selectElement.find('option'), function(option) {
21411              if (option.selected) {
21412                array.push(option.value);
21413              }
21414            });
21415            ctrl.$setViewValue(array);
21416          });
21417        });
21418      }
21419
21420      function setupAsOptions(scope, selectElement, ctrl) {
21421        var match;
21422
21423        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21424          throw ngOptionsMinErr('iexp',
21425            "Expected expression in form of " +
21426            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21427            " but got '{0}'. Element: {1}",
21428            optionsExp, startingTag(selectElement));
21429        }
21430
21431        var displayFn = $parse(match[2] || match[1]),
21432            valueName = match[4] || match[6],
21433            keyName = match[5],
21434            groupByFn = $parse(match[3] || ''),
21435            valueFn = $parse(match[2] ? match[1] : valueName),
21436            valuesFn = $parse(match[7]),
21437            track = match[8],
21438            trackFn = track ? $parse(match[8]) : null,
21439            // This is an array of array of existing option groups in DOM.
21440            // We try to reuse these if possible
21441            // - optionGroupsCache[0] is the options with no option group
21442            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21443            optionGroupsCache = [[{element: selectElement, label:''}]];
21444
21445        if (nullOption) {
21446          // compile the element since there might be bindings in it
21447          $compile(nullOption)(scope);
21448
21449          // remove the class, which is added automatically because we recompile the element and it
21450          // becomes the compilation root
21451          nullOption.removeClass('ng-scope');
21452
21453          // we need to remove it before calling selectElement.empty() because otherwise IE will
21454          // remove the label from the element. wtf?
21455          nullOption.remove();
21456        }
21457
21458        // clear contents, we'll add what's needed based on the model
21459        selectElement.empty();
21460
21461        selectElement.on('change', function() {
21462          scope.$apply(function() {
21463            var optionGroup,
21464                collection = valuesFn(scope) || [],
21465                locals = {},
21466                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21467
21468            if (multiple) {
21469              value = [];
21470              for (groupIndex = 0, groupLength = optionGroupsCache.length;
21471                   groupIndex < groupLength;
21472                   groupIndex++) {
21473                // list of options for that group. (first item has the parent)
21474                optionGroup = optionGroupsCache[groupIndex];
21475
21476                for(index = 1, length = optionGroup.length; index < length; index++) {
21477                  if ((optionElement = optionGroup[index].element)[0].selected) {
21478                    key = optionElement.val();
21479                    if (keyName) locals[keyName] = key;
21480                    if (trackFn) {
21481                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21482                        locals[valueName] = collection[trackIndex];
21483                        if (trackFn(scope, locals) == key) break;
21484                      }
21485                    } else {
21486                      locals[valueName] = collection[key];
21487                    }
21488                    value.push(valueFn(scope, locals));
21489                  }
21490                }
21491              }
21492            } else {
21493              key = selectElement.val();
21494              if (key == '?') {
21495                value = undefined;
21496              } else if (key === ''){
21497                value = null;
21498              } else {
21499                if (trackFn) {
21500                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21501                    locals[valueName] = collection[trackIndex];
21502                    if (trackFn(scope, locals) == key) {
21503                      value = valueFn(scope, locals);
21504                      break;
21505                    }
21506                  }
21507                } else {
21508                  locals[valueName] = collection[key];
21509                  if (keyName) locals[keyName] = key;
21510                  value = valueFn(scope, locals);
21511                }
21512              }
21513              // Update the null option's selected property here so $render cleans it up correctly
21514              if (optionGroupsCache[0].length > 1) {
21515                if (optionGroupsCache[0][1].id !== key) {
21516                  optionGroupsCache[0][1].selected = false;
21517                }
21518              }
21519            }
21520            ctrl.$setViewValue(value);
21521          });
21522        });
21523
21524        ctrl.$render = render;
21525
21526        // TODO(vojta): can't we optimize this ?
21527        scope.$watch(render);
21528
21529        function render() {
21530              // Temporary location for the option groups before we render them
21531          var optionGroups = {'':[]},
21532              optionGroupNames = [''],
21533              optionGroupName,
21534              optionGroup,
21535              option,
21536              existingParent, existingOptions, existingOption,
21537              modelValue = ctrl.$modelValue,
21538              values = valuesFn(scope) || [],
21539              keys = keyName ? sortedKeys(values) : values,
21540              key,
21541              groupLength, length,
21542              groupIndex, index,
21543              locals = {},
21544              selected,
21545              selectedSet = false, // nothing is selected yet
21546              lastElement,
21547              element,
21548              label;
21549
21550          if (multiple) {
21551            if (trackFn && isArray(modelValue)) {
21552              selectedSet = new HashMap([]);
21553              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21554                locals[valueName] = modelValue[trackIndex];
21555                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21556              }
21557            } else {
21558              selectedSet = new HashMap(modelValue);
21559            }
21560          }
21561
21562          // We now build up the list of options we need (we merge later)
21563          for (index = 0; length = keys.length, index < length; index++) {
21564
21565            key = index;
21566            if (keyName) {
21567              key = keys[index];
21568              if ( key.charAt(0) === '$' ) continue;
21569              locals[keyName] = key;
21570            }
21571
21572            locals[valueName] = values[key];
21573
21574            optionGroupName = groupByFn(scope, locals) || '';
21575            if (!(optionGroup = optionGroups[optionGroupName])) {
21576              optionGroup = optionGroups[optionGroupName] = [];
21577              optionGroupNames.push(optionGroupName);
21578            }
21579            if (multiple) {
21580              selected = isDefined(
21581                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21582              );
21583            } else {
21584              if (trackFn) {
21585                var modelCast = {};
21586                modelCast[valueName] = modelValue;
21587                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21588              } else {
21589                selected = modelValue === valueFn(scope, locals);
21590              }
21591              selectedSet = selectedSet || selected; // see if at least one item is selected
21592            }
21593            label = displayFn(scope, locals); // what will be seen by the user
21594
21595            // doing displayFn(scope, locals) || '' overwrites zero values
21596            label = isDefined(label) ? label : '';
21597            optionGroup.push({
21598              // either the index into array or key from object
21599              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
21600              label: label,
21601              selected: selected                   // determine if we should be selected
21602            });
21603          }
21604          if (!multiple) {
21605            if (nullOption || modelValue === null) {
21606              // insert null option if we have a placeholder, or the model is null
21607              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
21608            } else if (!selectedSet) {
21609              // option could not be found, we have to insert the undefined item
21610              optionGroups[''].unshift({id:'?', label:'', selected:true});
21611            }
21612          }
21613
21614          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
21615          for (groupIndex = 0, groupLength = optionGroupNames.length;
21616               groupIndex < groupLength;
21617               groupIndex++) {
21618            // current option group name or '' if no group
21619            optionGroupName = optionGroupNames[groupIndex];
21620
21621            // list of options for that group. (first item has the parent)
21622            optionGroup = optionGroups[optionGroupName];
21623
21624            if (optionGroupsCache.length <= groupIndex) {
21625              // we need to grow the optionGroups
21626              existingParent = {
21627                element: optGroupTemplate.clone().attr('label', optionGroupName),
21628                label: optionGroup.label
21629              };
21630              existingOptions = [existingParent];
21631              optionGroupsCache.push(existingOptions);
21632              selectElement.append(existingParent.element);
21633            } else {
21634              existingOptions = optionGroupsCache[groupIndex];
21635              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
21636
21637              // update the OPTGROUP label if not the same.
21638              if (existingParent.label != optionGroupName) {
21639                existingParent.element.attr('label', existingParent.label = optionGroupName);
21640              }
21641            }
21642
21643            lastElement = null;  // start at the beginning
21644            for(index = 0, length = optionGroup.length; index < length; index++) {
21645              option = optionGroup[index];
21646              if ((existingOption = existingOptions[index+1])) {
21647                // reuse elements
21648                lastElement = existingOption.element;
21649                if (existingOption.label !== option.label) {
21650                  lastElement.text(existingOption.label = option.label);
21651                }
21652                if (existingOption.id !== option.id) {
21653                  lastElement.val(existingOption.id = option.id);
21654                }
21655                // lastElement.prop('selected') provided by jQuery has side-effects
21656                if (existingOption.selected !== option.selected) {
21657                  lastElement.prop('selected', (existingOption.selected = option.selected));
21658                }
21659              } else {
21660                // grow elements
21661
21662                // if it's a null option
21663                if (option.id === '' && nullOption) {
21664                  // put back the pre-compiled element
21665                  element = nullOption;
21666                } else {
21667                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
21668                  // in this version of jQuery on some browser the .text() returns a string
21669                  // rather then the element.
21670                  (element = optionTemplate.clone())
21671                      .val(option.id)
21672                      .prop('selected', option.selected)
21673                      .text(option.label);
21674                }
21675
21676                existingOptions.push(existingOption = {
21677                    element: element,
21678                    label: option.label,
21679                    id: option.id,
21680                    selected: option.selected
21681                });
21682                if (lastElement) {
21683                  lastElement.after(element);
21684                } else {
21685                  existingParent.element.append(element);
21686                }
21687                lastElement = element;
21688              }
21689            }
21690            // remove any excessive OPTIONs in a group
21691            index++; // increment since the existingOptions[0] is parent element not OPTION
21692            while(existingOptions.length > index) {
21693              existingOptions.pop().element.remove();
21694            }
21695          }
21696          // remove any excessive OPTGROUPs from select
21697          while(optionGroupsCache.length > groupIndex) {
21698            optionGroupsCache.pop()[0].element.remove();
21699          }
21700        }
21701      }
21702    }
21703  };
21704}];
21705
21706var optionDirective = ['$interpolate', function($interpolate) {
21707  var nullSelectCtrl = {
21708    addOption: noop,
21709    removeOption: noop
21710  };
21711
21712  return {
21713    restrict: 'E',
21714    priority: 100,
21715    compile: function(element, attr) {
21716      if (isUndefined(attr.value)) {
21717        var interpolateFn = $interpolate(element.text(), true);
21718        if (!interpolateFn) {
21719          attr.$set('value', element.text());
21720        }
21721      }
21722
21723      return function (scope, element, attr) {
21724        var selectCtrlName = '$selectController',
21725            parent = element.parent(),
21726            selectCtrl = parent.data(selectCtrlName) ||
21727              parent.parent().data(selectCtrlName); // in case we are in optgroup
21728
21729        if (selectCtrl && selectCtrl.databound) {
21730          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
21731          // We don't want the view to drive the initialization of the model anyway.
21732          element.prop('selected', false);
21733        } else {
21734          selectCtrl = nullSelectCtrl;
21735        }
21736
21737        if (interpolateFn) {
21738          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
21739            attr.$set('value', newVal);
21740            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
21741            selectCtrl.addOption(newVal);
21742          });
21743        } else {
21744          selectCtrl.addOption(attr.value);
21745        }
21746
21747        element.on('$destroy', function() {
21748          selectCtrl.removeOption(attr.value);
21749        });
21750      };
21751    }
21752  };
21753}];
21754
21755var styleDirective = valueFn({
21756  restrict: 'E',
21757  terminal: true
21758});
21759
21760  if (window.angular.bootstrap) {
21761    //AngularJS is already loaded, so we can return here...
21762    console.log('WARNING: Tried to load angular more than once.');
21763    return;
21764  }
21765
21766  //try to bind to jquery now so that one can write angular.element().read()
21767  //but we will rebind on bootstrap again.
21768  bindJQuery();
21769
21770  publishExternalAPI(angular);
21771
21772  jqLite(document).ready(function() {
21773    angularInit(document, bootstrap);
21774  });
21775
21776})(window, document);
21777
21778!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>');

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.