PageSourceSearch

https://www.imperial-rac.com/wp-content/plugins/ng-filter/assets/js/vendor/angular/angular.js?ver=7.1.2

js imperial-rac.com collected 2026-10-04 02:41:31 UTC 779,159 bytes, 21,922 lines download raw bytes

1/**
2 * @license AngularJS v1.2.22
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.22/' +
72      (module ? module + '/' : '') + code;
73    for (i = 2; i < arguments.length; i++) {
74      message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
75        encodeURIComponent(stringify(arguments[i]));
76    }
77
78    return new Error(message);
79  };
80}
81
82/* We need to tell jshint what variables are being exported */
83/* global angular: true,
84    msie: true,
85    jqLite: true,
86    jQuery: true,
87    slice: true,
88    push: true,
89    toString: true,
90    ngMinErr: true,
91    angularModule: true,
92    nodeName_: true,
93    uid: true,
94    VALIDITY_STATE_PROPERTY: true,
95
96    lowercase: true,
97    uppercase: true,
98    manualLowercase: true,
99    manualUppercase: true,
100    nodeName_: true,
101    isArrayLike: true,
102    forEach: true,
103    sortedKeys: true,
104    forEachSorted: true,
105    reverseParams: true,
106    nextUid: true,
107    setHashKey: true,
108    extend: true,
109    int: true,
110    inherit: true,
111    noop: true,
112    identity: true,
113    valueFn: true,
114    isUndefined: true,
115    isDefined: true,
116    isObject: true,
117    isString: true,
118    isNumber: true,
119    isDate: true,
120    isArray: true,
121    isFunction: true,
122    isRegExp: true,
123    isWindow: true,
124    isScope: true,
125    isFile: true,
126    isBlob: true,
127    isBoolean: true,
128    isPromiseLike: true,
129    trim: true,
130    isElement: true,
131    makeMap: true,
132    map: true,
133    size: true,
134    includes: true,
135    indexOf: true,
136    arrayRemove: true,
137    isLeafNode: true,
138    copy: true,
139    shallowCopy: true,
140    equals: true,
141    csp: true,
142    concat: true,
143    sliceArgs: true,
144    bind: true,
145    toJsonReplacer: true,
146    toJson: true,
147    fromJson: true,
148    toBoolean: true,
149    startingTag: true,
150    tryDecodeURIComponent: true,
151    parseKeyValue: true,
152    toKeyValue: true,
153    encodeUriSegment: true,
154    encodeUriQuery: true,
155    angularInit: true,
156    bootstrap: true,
157    snake_case: true,
158    bindJQuery: true,
159    assertArg: true,
160    assertArgFn: true,
161    assertNotHasOwnProperty: true,
162    getter: true,
163    getBlockElements: true,
164    hasOwnProperty: true,
165*/
166
167////////////////////////////////////
168
169/**
170 * @ngdoc module
171 * @name ng
172 * @module ng
173 * @description
174 *
175 * # ng (core module)
176 * The ng module is loaded by default when an AngularJS application is started. The module itself
177 * contains the essential components for an AngularJS application to function. The table below
178 * lists a high level breakdown of each of the services/factories, filters, directives and testing
179 * components available within this core module.
180 *
181 * <div doc-module-components="ng"></div>
182 */
183
184// The name of a form control's ValidityState property.
185// This is used so that it's possible for internal tests to create mock ValidityStates.
186var VALIDITY_STATE_PROPERTY = 'validity';
187
188/**
189 * @ngdoc function
190 * @name angular.lowercase
191 * @module ng
192 * @kind function
193 *
194 * @description Converts the specified string to lowercase.
195 * @param {string} string String to be converted to lowercase.
196 * @returns {string} Lowercased string.
197 */
198var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
199var hasOwnProperty = Object.prototype.hasOwnProperty;
200
201/**
202 * @ngdoc function
203 * @name angular.uppercase
204 * @module ng
205 * @kind function
206 *
207 * @description Converts the specified string to uppercase.
208 * @param {string} string String to be converted to uppercase.
209 * @returns {string} Uppercased string.
210 */
211var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
212
213
214var manualLowercase = function(s) {
215  /* jshint bitwise: false */
216  return isString(s)
217      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
218      : s;
219};
220var manualUppercase = function(s) {
221  /* jshint bitwise: false */
222  return isString(s)
223      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
224      : s;
225};
226
227
228// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
229// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
230// with correct but slower alternatives.
231if ('i' !== 'I'.toLowerCase()) {
232  lowercase = manualLowercase;
233  uppercase = manualUppercase;
234}
235
236
237var /** holds major version number for IE or NaN for real browsers */
238    msie,
239    jqLite,           // delay binding since jQuery could be loaded after us.
240    jQuery,           // delay binding
241    slice             = [].slice,
242    push              = [].push,
243    toString          = Object.prototype.toString,
244    ngMinErr          = minErr('ng'),
245
246    /** @name angular */
247    angular           = window.angular || (window.angular = {}),
248    angularModule,
249    nodeName_,
250    uid               = ['0', '0', '0'];
251
252/**
253 * IE 11 changed the format of the UserAgent string.
254 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
255 */
256msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
257if (isNaN(msie)) {
258  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
259}
260
261
262/**
263 * @private
264 * @param {*} obj
265 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
266 *                   String ...)
267 */
268function isArrayLike(obj) {
269  if (obj == null || isWindow(obj)) {
270    return false;
271  }
272
273  var length = obj.length;
274
275  if (obj.nodeType === 1 && length) {
276    return true;
277  }
278
279  return isString(obj) || isArray(obj) || length === 0 ||
280         typeof length === 'number' && length > 0 && (length - 1) in obj;
281}
282
283/**
284 * @ngdoc function
285 * @name angular.forEach
286 * @module ng
287 * @kind function
288 *
289 * @description
290 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
291 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
292 * is the value of an object property or an array element and `key` is the object property key or
293 * array element index. Specifying a `context` for the function is optional.
294 *
295 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
296 * using the `hasOwnProperty` method.
297 *
298   ```js
299     var values = {name: 'misko', gender: 'male'};
300     var log = [];
301     angular.forEach(values, function(value, key) {
302       this.push(key + ': ' + value);
303     }, log);
304     expect(log).toEqual(['name: misko', 'gender: male']);
305   ```
306 *
307 * @param {Object|Array} obj Object to iterate over.
308 * @param {Function} iterator Iterator function.
309 * @param {Object=} context Object to become context (`this`) for the iterator function.
310 * @returns {Object|Array} Reference to `obj`.
311 */
312function forEach(obj, iterator, context) {
313  var key;
314  if (obj) {
315    if (isFunction(obj)) {
316      for (key in obj) {
317        // Need to check if hasOwnProperty exists,
318        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
319        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
320          iterator.call(context, obj[key], key);
321        }
322      }
323    } else if (isArray(obj) || isArrayLike(obj)) {
324      for (key = 0; key < obj.length; key++) {
325        iterator.call(context, obj[key], key);
326      }
327    }
327 else if (obj.forEach && obj.forEach !== forEach) {
328        obj.forEach(iterator, context);
329    } else {
330      for (key in obj) {
331        if (obj.hasOwnProperty(key)) {
332          iterator.call(context, obj[key], key);
333        }
334      }
335    }
336  }
337  return obj;
338}
339
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
665function isPromiseLike(obj) {
666  return obj && isFunction(obj.then);
667}
668
669
670var trim = (function() {
671  // native trim is way faster: http://jsperf.com/angular-trim-test
672  // but IE doesn't have it... :-(
673  // TODO: we should move this into IE/ES5 polyfill
674  if (!String.prototype.trim) {
675    return function(value) {
676      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
677    };
678  }
679  return function(value) {
680    return isString(value) ? value.trim() : value;
681  };
682})();
683
684
685/**
686 * @ngdoc function
687 * @name angular.isElement
688 * @module ng
689 * @kind function
690 *
691 * @description
692 * Determines if a reference is a DOM element (or wrapped jQuery element).
693 *
694 * @param {*} value Reference to check.
695 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
696 */
697function isElement(node) {
698  return !!(node &&
699    (node.nodeName  // we are a direct element
700    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
701}
702
703/**
704 * @param str 'key1,key2,...'
705 * @returns {object} in the form of {key1:true, key2:true, ...}
706 */
707function makeMap(str) {
708  var obj = {}, items = str.split(","), i;
709  for ( i = 0; i < items.length; i++ )
710    obj[ items[i] ] = true;
711  return obj;
712}
713
714
715if (msie < 9) {
716  nodeName_ = function(element) {
717    element = element.nodeName ? element : element[0];
718    return (element.scopeName && element.scopeName != 'HTML')
719      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
720  };
721} else {
722  nodeName_ = function(element) {
723    return element.nodeName ? element.nodeName : element[0].nodeName;
724  };
725}
726
727
728function map(obj, iterator, context) {
729  var results = [];
730  forEach(obj, function(value, index, list) {
731    results.push(iterator.call(context, value, index, list));
732  });
733  return results;
734}
735
736
737/**
738 * @description
739 * Determines the number of elements in an array, the number of properties an object has, or
740 * the length of a string.
741 *
742 * Note: This function is used to augment the Object type in Angular expressions. See
743 * {@link angular.Object} for more information about Angular arrays.
744 *
745 * @param {Object|Array|string} obj Object, array, or string to inspect.
746 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
747 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
748 */
749function size(obj, ownPropsOnly) {
750  var count = 0, key;
751
752  if (isArray(obj) || isString(obj)) {
753    return obj.length;
754  } else if (isObject(obj)) {
755    for (key in obj)
756      if (!ownPropsOnly || obj.hasOwnProperty(key))
757        count++;
758  }
759
760  return count;
761}
762
763
764function includes(array, obj) {
765  return indexOf(array, obj) != -1;
766}
767
768function indexOf(array, obj) {
769  if (array.indexOf) return array.indexOf(obj);
770
771  for (var i = 0; i < array.length; i++) {
772    if (obj === array[i]) return i;
773  }
774  return -1;
775}
776
777function arrayRemove(array, value) {
778  var index = indexOf(array, value);
779  if (index >=0)
780    array.splice(index, 1);
781  return value;
782}
783
784function isLeafNode (node) {
785  if (node) {
786    switch (node.nodeName) {
787    case "OPTION":
788    case "PRE":
789    case "TITLE":
790      return true;
791    }
792  }
793  return false;
794}
795
796/**
797 * @ngdoc function
798 * @name angular.copy
799 * @module ng
800 * @kind function
801 *
802 * @description
803 * Creates a deep copy of `source`, which should be an object or an array.
804 *
805 * * If no destination is supplied, a copy of the object or array is created.
806 * * If a destination is provided, all of its elements (for array) or properties (for objects)
807 *   are deleted and then all elements/properties from the source are copied to it.
808 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
809 * * If `source` is identical to 'destination' an exception will be thrown.
810 *
811 * @param {*} source The source that will be used to make a copy.
812 *                   Can be any type, including primitives, `null`, and `undefined`.
813 * @param {(Object|Array)=} destination Destination into which the source is copied. If
814 *     provided, must be of the same type as `source`.
815 * @returns {*} The copy or updated `destination`, if `destination` was specified.
816 *
817 * @example
818 <example module="copyExample">
819 <file name="index.html">
820 <div ng-controller="ExampleController">
821 <form novalidate class="simple-form">
822 Name: <input type="text" ng-model="user.name" /><br />
823 E-mail: <input type="email" ng-model="user.email" /><br />
824 Gender: <input type="radio" ng-model="user.gender" value="male" />male
825 <input type="radio" ng-model="user.gender" value="female" />female<br />
826 <button ng-click="reset()">RESET</button>
827 <button ng-click="update(user)">SAVE</button>
828 </form>
829 <pre>form = {{user | json}}</pre>
830 <pre>master = {{master | json}}</pre>
831 </div>
832
833 <script>
834  angular.module('copyExample', [])
835    .controller('ExampleController', ['$scope', function($scope) {
836      $scope.master= {};
837
838      $scope.update = function(user) {
839        // Example with 1 argument
840        $scope.master= angular.copy(user);
841      };
842
843      $scope.reset = function() {
844        // Example with 2 arguments
845        angular.copy($scope.master, $scope.user);
846      };
847
848      $scope.reset();
849    }]);
850 </script>
851 </file>
852 </example>
853 */
854function copy(source, destination, stackSource, stackDest) {
855  if (isWindow(source) || isScope(source)) {
856    throw ngMinErr('cpws',
857      "Can't copy! Making copies of Window or Scope instances is not supported.");
858  }
859
860  if (!destination) {
861    destination = source;
862    if (source) {
863      if (isArray(source)) {
864        destination = copy(source, [], stackSource, stackDest);
865      } else if (isDate(source)) {
866        destination = new Date(source.getTime());
867      } else if (isRegExp(source)) {
868        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
869        destination.lastIndex = source.lastIndex;
870      } else if (isObject(source)) {
871        destination = copy(source, {}, stackSource, stackDest);
872      }
873    }
874  } else {
875    if (source === destination) throw ngMinErr('cpi',
876      "Can't copy! Source and destination are identical.");
877
878    stackSource = stackSource || [];
879    stackDest = stackDest || [];
880
881    if (isObject(source)) {
882      var index = indexOf(stackSource, source);
883      if (index !== -1) return stackDest[index];
884
885      stackSource.push(source);
886      stackDest.push(destination);
887    }
888
889    var result;
890    if (isArray(source)) {
891      destination.length = 0;
892      for ( var i = 0; i < source.length; i++) {
893        result = copy(source[i], null, stackSource, stackDest);
894        if (isObject(source[i])) {
895          stackSource.push(source[i]);
896          stackDest.push(result);
897        }
898        destination.push(result);
899      }
900    } else {
901      var h = destination.$$hashKey;
902      forEach(destination, function(value, key) {
903        delete destination[key];
904      });
905      for ( var key in source) {
906        result = copy(source[key], null, stackSource, stackDest);
907        if (isObject(source[key])) {
908          stackSource.push(source[key]);
909          stackDest.push(result);
910        }
911        destination[key] = result;
912      }
913      setHashKey(destination,h);
914    }
915
916  }
917  return destination;
918}
919
920/**
921 * Creates a shallow copy of an object, an array or a primitive
922 */
923function shallowCopy(src, dst) {
924  if (isArray(src)) {
925    dst = dst || [];
926
927    for ( var i = 0; i < src.length; i++) {
928      dst[i] = src[i];
929    }
930  } else if (isObject(src)) {
931    dst = dst || {};
932
933    for (var key in src) {
934      if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
935        dst[key] = src[key];
936      }
937    }
938  }
939
940  return dst || src;
941}
942
943
944/**
945 * @ngdoc function
946 * @name angular.equals
947 * @module ng
948 * @kind function
949 *
950 * @description
951 * Determines if two objects or two values are equivalent. Supports value types, regular
952 * expressions, arrays and objects.
953 *
954 * Two objects or values are considered equivalent if at least one of the following is true:
955 *
956 * * Both objects or values pass `===` comparison.
957 * * Both objects or values are of the same type and all of their properties are equal by
958 *   comparing them with `angular.equals`.
959 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
960 * * Both values represent the same regular expression (In JavaScript,
961 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
962 *   representation matches).
963 *
964 * During a property comparison, properties of `function` type and properties with names
965 * that begin with `$` are ignored.
966 *
967 * Scope and DOMWindow objects are being compared only by identify (`===`).
968 *
969 * @param {*} o1 Object or value to compare.
970 * @param {*} o2 Object or value to compare.
971 * @returns {boolean} True if arguments are equal.
972 */
973function equals(o1, o2) {
974  if (o1 === o2) return true;
975  if (o1 === null || o2 === null) return false;
976  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
977  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
978  if (t1 == t2) {
979    if (t1 == 'object') {
980      if (isArray(o1)) {
981        if (!isArray(o2)) return false;
982        if ((length = o1.length) == o2.length) {
983          for(key=0; key<length; key++) {
984            if (!equals(o1[key], o2[key])) return false;
985          }
986          return true;
987        }
988      } else if (isDate(o1)) {
989        return isDate(o2) && o1.getTime() == o2.getTime();
990      } else if (isRegExp(o1) && isRegExp(o2)) {
991        return o1.toString() == o2.toString();
992      } else {
993        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
994        keySet = {};
995        for(key in o1) {
996          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
997          if (!equals(o1[key], o2[key])) return false;
998          keySet[key] = true;
999        }
1000        for(key in o2) {
1001          if (!keySet.hasOwnProperty(key) &&
1002              key.charAt(0) !== '$' &&
1003              o2[key] !== undefined &&
1004              !isFunction(o2[key])) return false;
1005        }
1006        return true;
1007      }
1008    }
1009  }
1010  return false;
1011}
1012
1013var csp = function() {
1014  if (isDefined(csp.isActive_)) return csp.isActive_;
1015
1016  var active = !!(document.querySelector('[ng-csp]') ||
1017                  document.querySelector('[data-ng-csp]'));
1018
1019  if (!active) {
1020    try {
1021      /* jshint -W031, -W054 */
1022      new Function('');
1023      /* jshint +W031, +W054 */
1024    } catch (e) {
1025      active = true;
1026    }
1027  }
1028
1029  return (csp.isActive_ = active);
1030};
1031
1032
1033
1034function concat(array1, array2, index) {
1035  return array1.concat(slice.call(array2, index));
1036}
1037
1038function sliceArgs(args, startIndex) {
1039  return slice.call(args, startIndex || 0);
1040}
1041
1042
1043/* jshint -W101 */
1044/**
1045 * @ngdoc function
1046 * @name angular.bind
1047 * @module ng
1048 * @kind function
1049 *
1050 * @description
1051 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1052 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1053 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1054 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1055 *
1056 * @param {Object} self Context which `fn` should be evaluated in.
1057 * @param {function()} fn Function to be bound.
1058 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1059 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1060 */
1061/* jshint +W101 */
1062function bind(self, fn) {
1063  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1064  if (isFunction(fn) && !(fn instanceof RegExp)) {
1065    return curryArgs.length
1066      ? function() {
1067          return arguments.length
1068            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1069            : fn.apply(self, curryArgs);
1070        }
1071      : function() {
1072          return arguments.length
1073            ? fn.apply(self, arguments)
1074            : fn.call(self);
1075        };
1076  } else {
1077    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1078    return fn;
1079  }
1080}
1081
1082
1083function toJsonReplacer(key, value) {
1084  var val = value;
1085
1086  if (typeof key === 'string' && key.charAt(0) === '$') {
1087    val = undefined;
1088  } else if (isWindow(value)) {
1089    val = '$WINDOW';
1090  } else if (value &&  document === value) {
1091    val = '$DOCUMENT';
1092  } else if (isScope(value)) {
1093    val = '$SCOPE';
1094  }
1095
1096  return val;
1097}
1098
1099
1100/**
1101 * @ngdoc function
1102 * @name angular.toJson
1103 * @module ng
1104 * @kind function
1105 *
1106 * @description
1107 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1108 * stripped since angular uses this notation internally.
1109 *
1110 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1111 * @param {boolean=}
1111 pretty If set to true, the JSON output will contain newlines and whitespace.
1112 * @returns {string|undefined} JSON-ified string representing `obj`.
1113 */
1114function toJson(obj, pretty) {
1115  if (typeof obj === 'undefined') return undefined;
1116  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1117}
1118
1119
1120/**
1121 * @ngdoc function
1122 * @name angular.fromJson
1123 * @module ng
1124 * @kind function
1125 *
1126 * @description
1127 * Deserializes a JSON string.
1128 *
1129 * @param {string} json JSON string to deserialize.
1130 * @returns {Object|Array|string|number} Deserialized thingy.
1131 */
1132function fromJson(json) {
1133  return isString(json)
1134      ? JSON.parse(json)
1135      : json;
1136}
1137
1138
1139function toBoolean(value) {
1140  if (typeof value === 'function') {
1141    value = true;
1142  } else if (value && value.length !== 0) {
1143    var v = lowercase("" + value);
1144    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1145  } else {
1146    value = false;
1147  }
1148  return value;
1149}
1150
1151/**
1152 * @returns {string} Returns the string representation of the element.
1153 */
1154function startingTag(element) {
1155  element = jqLite(element).clone();
1156  try {
1157    // turns out IE does not let you set .html() on elements which
1158    // are not allowed to have children. So we just ignore it.
1159    element.empty();
1160  } catch(e) {}
1161  // As Per DOM Standards
1162  var TEXT_NODE = 3;
1163  var elemHtml = jqLite('<div>').append(element).html();
1164  try {
1165    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1166        elemHtml.
1167          match(/^(<[^>]+>)/)[1].
1168          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1169  } catch(e) {
1170    return lowercase(elemHtml);
1171  }
1172
1173}
1174
1175
1176/////////////////////////////////////////////////
1177
1178/**
1179 * Tries to decode the URI component without throwing an exception.
1180 *
1181 * @private
1182 * @param str value potential URI component to check.
1183 * @returns {boolean} True if `value` can be decoded
1184 * with the decodeURIComponent function.
1185 */
1186function tryDecodeURIComponent(value) {
1187  try {
1188    return decodeURIComponent(value);
1189  } catch(e) {
1190    // Ignore any invalid uri component
1191  }
1192}
1193
1194
1195/**
1196 * Parses an escaped url query string into key-value pairs.
1197 * @returns {Object.<string,boolean|Array>}
1198 */
1199function parseKeyValue(/**string*/keyValue) {
1200  var obj = {}, key_value, key;
1201  forEach((keyValue || "").split('&'), function(keyValue) {
1202    if ( keyValue ) {
1203      key_value = keyValue.replace(/\+/g,'%20').split('=');
1204      key = tryDecodeURIComponent(key_value[0]);
1205      if ( isDefined(key) ) {
1206        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1207        if (!hasOwnProperty.call(obj, key)) {
1208          obj[key] = val;
1209        } else if(isArray(obj[key])) {
1210          obj[key].push(val);
1211        } else {
1212          obj[key] = [obj[key],val];
1213        }
1214      }
1215    }
1216  });
1217  return obj;
1218}
1219
1220function toKeyValue(obj) {
1221  var parts = [];
1222  forEach(obj, function(value, key) {
1223    if (isArray(value)) {
1224      forEach(value, function(arrayValue) {
1225        parts.push(encodeUriQuery(key, true) +
1226                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1227      });
1228    } else {
1229    parts.push(encodeUriQuery(key, true) +
1230               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1231    }
1232  });
1233  return parts.length ? parts.join('&') : '';
1234}
1235
1236
1237/**
1238 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1239 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1240 * segments:
1241 *    segment       = *pchar
1242 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1243 *    pct-encoded   = "%" HEXDIG HEXDIG
1244 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1245 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1246 *                     / "*" / "+" / "," / ";" / "="
1247 */
1248function encodeUriSegment(val) {
1249  return encodeUriQuery(val, true).
1250             replace(/%26/gi, '&').
1251             replace(/%3D/gi, '=').
1252             replace(/%2B/gi, '+');
1253}
1254
1255
1256/**
1257 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1258 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1259 * encoded per http://tools.ietf.org/html/rfc3986:
1260 *    query       = *( pchar / "/" / "?" )
1261 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1262 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1263 *    pct-encoded   = "%" HEXDIG HEXDIG
1264 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1265 *                     / "*" / "+" / "," / ";" / "="
1266 */
1267function encodeUriQuery(val, pctEncodeSpaces) {
1268  return encodeURIComponent(val).
1269             replace(/%40/gi, '@').
1270             replace(/%3A/gi, ':').
1271             replace(/%24/g, '$').
1272             replace(/%2C/gi, ',').
1273             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1274}
1275
1276
1277/**
1278 * @ngdoc directive
1279 * @name ngApp
1280 * @module ng
1281 *
1282 * @element ANY
1283 * @param {angular.Module} ngApp an optional application
1284 *   {@link angular.module module} name to load.
1285 *
1286 * @description
1287 *
1288 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1289 * designates the **root element** of the application and is typically placed near the root element
1290 * of the page - e.g. on the `<body>` or `<html>` tags.
1291 *
1292 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
1292p`
1293 * found in the document will be used to define the root element to auto-bootstrap as an
1294 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1295 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1296 *
1297 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1298 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1299 * should contain the application code needed or have dependencies on other modules that will
1300 * contain the code. See {@link angular.module} for more information.
1301 *
1302 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1303 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1304 * would not be resolved to `3`.
1305 *
1306 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1307 *
1308 <example module="ngAppDemo">
1309   <file name="index.html">
1310   <div ng-controller="ngAppDemoController">
1311     I can add: {{a}} + {{b}} =  {{ a+b }}
1312   </div>
1313   </file>
1314   <file name="script.js">
1315   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1316     $scope.a = 1;
1317     $scope.b = 2;
1318   });
1319   </file>
1320 </example>
1321 *
1322 */
1323function angularInit(element, bootstrap) {
1324  var elements = [element],
1325      appElement,
1326      module,
1327      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1328      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1329
1330  function append(element) {
1331    element && elements.push(element);
1332  }
1333
1334  forEach(names, function(name) {
1335    names[name] = true;
1336    append(document.getElementById(name));
1337    name = name.replace(':', '\\:');
1338    if (element.querySelectorAll) {
1339      forEach(element.querySelectorAll('.' + name), append);
1340      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1341      forEach(element.querySelectorAll('[' + name + ']'), append);
1342    }
1343  });
1344
1345  forEach(elements, function(element) {
1346    if (!appElement) {
1347      var className = ' ' + element.className + ' ';
1348      var match = NG_APP_CLASS_REGEXP.exec(className);
1349      if (match) {
1350        appElement = element;
1351        module = (match[2] || '').replace(/\s+/g, ',');
1352      } else {
1353        forEach(element.attributes, function(attr) {
1354          if (!appElement && names[attr.name]) {
1355            appElement = element;
1356            module = attr.value;
1357          }
1358        });
1359      }
1360    }
1361  });
1362  if (appElement) {
1363    bootstrap(appElement, module ? [module] : []);
1364  }
1365}
1366
1367/**
1368 * @ngdoc function
1369 * @name angular.bootstrap
1370 * @module ng
1371 * @description
1372 * Use this function to manually start up angular application.
1373 *
1374 * See: {@link guide/bootstrap Bootstrap}
1375 *
1376 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1377 * They must use {@link ng.directive:ngApp ngApp}.
1378 *
1379 * Angular will detect if it has been loaded into the browser more than once and only allow the
1380 * first loaded script to be bootstrapped and will report a warning to the browser console for
1381 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1382 * multiple instances of Angular try to work on the DOM.
1383 *
1384 * <example name="multi-bootstrap" module="multi-bootstrap">
1385 * <file name="index.html">
1386 * <script src="../../../angular.js"></script>
1387 * <div ng-controller="BrokenTable">
1388 *   <table>
1389 *   <tr>
1390 *     <th ng-repeat="heading in headings">{{heading}}</th>
1391 *   </tr>
1392 *   <tr ng-repeat="filling in fillings">
1393 *     <td ng-repeat="fill in filling">{{fill}}</td>
1394 *   </tr>
1395 * </table>
1396 * </div>
1397 * </file>
1398 * <file name="controller.js">
1399 * var app = angular.module('multi-bootstrap', [])
1400 *
1401 * .controller('BrokenTable', function($scope) {
1402 *     $scope.headings = ['One', 'Two', 'Three'];
1403 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1404 * });
1405 * </file>
1406 * <file name="protractor.js" type="protractor">
1407 * it('should only insert one table cell for each item in $scope.fillings', function() {
1408 *  expect(element.all(by.css('td')).count())
1409 *      .toBe(9);
1410 * });
1411 * </file>
1412 * </example>
1413 *
1414 * @param {DOMElement} element DOM element which is the root of angular application.
1415 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1416 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1417 *     function that will be invoked by the injector as a run block.
1418 *     See: {@link angular.module modules}
1419 * @returns {auto.$injector} Returns the newly created injector for this app.
1420 */
1421function bootstrap(element, modules) {
1422  var doBootstrap = function() {
1423    element = jqLite(element);
1424
1425    if (element.injector()) {
1426      var tag = (element[0] === document) ? 'document' : startingTag(element);
1427      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1428    }
1429
1430    modules = modules || [];
1431    modules.unshift(['$provide', function($provide) {
1432      $provide.value('$rootElement', element);
1433    }]);
1434    modules.unshift('ng');
1435    var injector = createInjector(modules);
1436    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1437       function(scope, element, compile, injector, animate) {
1438        scope.$apply(function() {
1439          element.data('$injector', injector);
1440          compile(element)(scope);
1441        });
1442      }]
1443    );
1444    return injector;
1445  };
1446
1447  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1448
1449  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1450    return doBootstrap();
1451  }
1452
1453  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1454  angular.resumeBootstrap = function(extraModules) {
1455    forEach(extraModules, function(module) {
1456      modules.push(module);
1457    });
1458    doBootstrap();
1459  };
1460}
1461
1462var SNAKE_CASE_REGEXP = /[A-Z]/g;
1463function snake_case(name, separator) {
1464  separator = separator || '_';
1465  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1466    return (pos ? separator : '') + letter.toLowerCase();
1467  });
1468}
1469
1470function bindJQuery() {
1471  // bind to jQuery if present;
1472  jQuery = window.jQuery;
1473  // Use jQuery if it exists with proper functionality, otherwise default to us.
1474  // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
1475  if (jQuery && jQuery.fn.on) {
1476    jqLite = jQuery;
1477    extend(jQuery.fn, {
1478      scope: JQLitePrototype.scope,
1479      isolateScope: JQLitePrototype.isolateScope,
1480      controller: JQLitePrototype.controller,
1481      injector: JQLitePrototype.injector,
1482      inheritedData: JQLitePrototype.inheritedData
1483    });
1484    // Method signature:
1485    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1486    jqLitePatchJQueryRemove('remove', true, true, false);
1487    jqLitePatchJQueryRemove('empty', false, false, false);
1488    jqLitePatchJQueryRemove('html', false, false, true);
1489  } else {
1490    jqLite = JQLite;
1491  }
1492  angular.element = jqLite;
1493}
1494
1495/**
1496 * throw error if the argument is falsy.
1497 */
1498function assertArg(arg, name, reason) {
1499  if (!arg) {
1500    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1501  }
1502  return arg;
1503}
1504
1505function assertArgFn(arg, name, acceptArrayAnnotation) {
1506  if (acceptArrayAnnotation && isArray(arg)) {
1507      arg = arg[arg.length - 1];
1508  }
1509
1510  assertArg(isFunction(arg), name, 'not a function, got ' +
1511      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1512  return arg;
1513}
1514
1515/**
1516 * throw error if the name given is hasOwnProperty
1517 * @param  {String} name    the name to test
1518 * @param  {String} context the context in which the name is used, such as module or directive
1519 */
1520function assertNotHasOwnProperty(name, context) {
1521  if (name === 'hasOwnProperty') {
1522    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1523  }
1524}
1525
1526/**
1527 * Return the value accessible from the object by path. Any undefined traversals are ignored
1528 * @param {Object} obj starting object
1529 * @param {String} path path to traverse
1530 * @param {boolean} [bindFnToScope=true]
1531 * @returns {Object} value as accessible by path
1532 */
1533//TODO(misko): this function needs to be removed
1534function getter(obj, path, bindFnToScope) {
1535  if (!path) return obj;
1536  var keys = path.split('.');
1537  var key;
1538  var lastInstance = obj;
1539  var len = keys.length;
1540
1541  for (var i = 0; i < len; i++) {
1542    key = keys[i];
1543    if (obj) {
1544      obj = (lastInstance = obj)[key];
1545    }
1546  }
1547  if (!bindFnToScope && isFunction(obj)) {
1548    return bind(lastInstance, obj);
1549  }
1550  return obj;
1551}
1552
1553/**
1554 * Return the DOM siblings between the first and last node in the given array.
1555 * @param {Array} array like object
1556 * @returns {DOMElement}
1556 object containing the elements
1557 */
1558function getBlockElements(nodes) {
1559  var startNode = nodes[0],
1560      endNode = nodes[nodes.length - 1];
1561  if (startNode === endNode) {
1562    return jqLite(startNode);
1563  }
1564
1565  var element = startNode;
1566  var elements = [element];
1567
1568  do {
1569    element = element.nextSibling;
1570    if (!element) break;
1571    elements.push(element);
1572  } while (element !== endNode);
1573
1574  return jqLite(elements);
1575}
1576
1577/**
1578 * @ngdoc type
1579 * @name angular.Module
1580 * @module ng
1581 * @description
1582 *
1583 * Interface for configuring angular {@link angular.module modules}.
1584 */
1585
1586function setupModuleLoader(window) {
1587
1588  var $injectorMinErr = minErr('$injector');
1589  var ngMinErr = minErr('ng');
1590
1591  function ensure(obj, name, factory) {
1592    return obj[name] || (obj[name] = factory());
1593  }
1594
1595  var angular = ensure(window, 'angular', Object);
1596
1597  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1598  angular.$$minErr = angular.$$minErr || minErr;
1599
1600  return ensure(angular, 'module', function() {
1601    /** @type {Object.<string, angular.Module>} */
1602    var modules = {};
1603
1604    /**
1605     * @ngdoc function
1606     * @name angular.module
1607     * @module ng
1608     * @description
1609     *
1610     * The `angular.module` is a global place for creating, registering and retrieving Angular
1611     * modules.
1612     * All modules (angular core or 3rd party) that should be available to an application must be
1613     * registered using this mechanism.
1614     *
1615     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1616     * existing module (the name passed as the first argument to `module`) is retrieved.
1617     *
1618     *
1619     * # Module
1620     *
1621     * A module is a collection of services, directives, controllers, filters, and configuration information.
1622     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1623     *
1624     * ```js
1625     * // Create a new module
1626     * var myModule = angular.module('myModule', []);
1627     *
1628     * // register a new service
1629     * myModule.value('appName', 'MyCoolApp');
1630     *
1631     * // configure existing services inside initialization blocks.
1632     * myModule.config(['$locationProvider', function($locationProvider) {
1633     *   // Configure existing providers
1634     *   $locationProvider.hashPrefix('!');
1635     * }]);
1636     * ```
1637     *
1638     * Then you can create an injector and load your modules like this:
1639     *
1640     * ```js
1641     * var injector = angular.injector(['ng', 'myModule'])
1642     * ```
1643     *
1644     * However it's more likely that you'll just use
1645     * {@link ng.directive:ngApp ngApp} or
1646     * {@link angular.bootstrap} to simplify this process for you.
1647     *
1648     * @param {!string} name The name of the module to create or retrieve.
1649     * @param {!Array.<string>=} requires If specified then new module is being created. If
1650     *        unspecified then the module is being retrieved for further configuration.
1651     * @param {Function=} configFn Optional configuration function for the module. Same as
1652     *        {@link angular.Module#config Module#config()}.
1653     * @returns {module} new module with the {@link angular.Module} api.
1654     */
1655    return function module(name, requires, configFn) {
1656      var assertNotHasOwnProperty = function(name, context) {
1657        if (name === 'hasOwnProperty') {
1658          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1659        }
1660      };
1661
1662      assertNotHasOwnProperty(name, 'module');
1663      if (requires && modules.hasOwnProperty(name)) {
1664        modules[name] = null;
1665      }
1666      return ensure(modules, name, function() {
1667        if (!requires) {
1668          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1669             "the module name or forgot to load it. If registering a module ensure that you " +
1670             "specify the dependencies as the second argument.", name);
1671        }
1672
1673        /** @type {!Array.<Array.<*>>} */
1674        var invokeQueue = [];
1675
1676        /** @type {!Array.<Function>} */
1677        var runBlocks = [];
1678
1679        var config = invokeLater('$injector', 'invoke');
1680
1681        /** @type {angular.Module} */
1682        var moduleInstance = {
1683          // Private state
1684          _invokeQueue: invokeQueue,
1685          _runBlocks: runBlocks,
1686
1687          /**
1688           * @ngdoc property
1689           * @name angular.Module#requires
1690           * @module ng
1691           * @returns {Array.<string>} List of module names which must be loaded before this module.
1692           * @description
1693           * Holds the list of modules which the injector will load before the current module is
1694           * loaded.
1695           */
1696          requires: requires,
1697
1698          /**
1699           * @ngdoc property
1700           * @name angular.Module#name
1701           * @module ng
1702           * @returns {string} Name of the module.
1703           * @description
1704           */
1705          name: name,
1706
1707
1708          /**
1709           * @ngdoc method
1710           * @name angular.Module#provider
1711           * @module ng
1712           * @param {string} name service name
1713           * @param {Function} providerType Construction function for creating new instance of the
1714           *                                service.
1715           * @description
1716           * See {@link auto.$provide#provider $provide.provider()}.
1717           */
1718          provider: invokeLater('$provide', 'provider'),
1719
1720          /**
1721           * @ngdoc method
1722           * @name angular.Module#factory
1723           * @module ng
1724           * @param {string} name service name
1725           * @param {Function} providerFunction Function for creating new instance of the service.
1726           * @description
1727           * See {@link auto.$provide#factory $provide.factory()}.
1728           */
1729          factory: invokeLater('$provide', 'factory'),
1730
1731          /**
1732           * @ngdoc method
1733           * @name angular.Module#service
1734           * @module ng
1735           * @param {string} name service name
1736           * @param {Function} constructor A constructor function that will be instantiated.
1737           * @description
1738           * See {@link auto.$provide#service $provide.service()}.
1739           */
1740          service: invokeLater('$provide', 'service'),
1741
1742          /**
1743           * @ngdoc method
1744           * @name angular.Module#value
1745           * @module ng
1746           * @param {string} name service name
1747           * @param {*} object Service instance object.
1748           * @description
1749           * See {@link auto.$provide#value $provide.value()}.
1750           */
1751          value: invokeLater('$provide', 'value'),
1752
1753          /**
1754           * @ngdoc method
1755           * @name angular.Module#constant
1756           * @module ng
1757           * @param {string} name constant name
1758           * @param {*} object Constant value.
1759           * @description
1760           * Because the constant are fixed, they get applied before other provide methods.
1761           * See {@link auto.$provide#constant $provide.constant()}.
1762           */
1763          constant: invokeLater('$provide', 'constant', 'unshift'),
1764
1765          /**
1766           * @ngdoc method
1767           * @name angular.Module#animation
1768           * @module ng
1769           * @param {string} name animation name
1770           * @param {Function} animationFactory Factory function for creating new instance of an
1771           *                                    animation.
1772           * @description
1773           *
1774           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1775           *
1776           *
1777           * Defines an animation hook that can be later used with
1778           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1779           *
1780           * ```js
1781           * module.animation('.animation-name', function($inject1, $inject2) {
1782           *   return {
1783           *     eventName : function(element, done) {
1784           *       //code to run the animation
1785           *       //once complete, then run done()
1786           *       return function cancellationFunction(element) {
1787           *         //code to cancel the animation
1788           *       }
1789           *     }
1790           *   }
1791           * })
1792           * ```
1793           *
1794           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1795           * {@link ngAnimate ngAnimate module} for more information.
1796           */
1797          animation: invokeLater('$animateProvider', 'register'),
1798
1799          /**
1800           * @ngdoc method
1801           * @name angular.Module#filter
1802           * @module ng
1803           * @param {string} name Filter name.
1804           * @param {Function} filterFactory Factory function for creating new instance of filter.
1805           * @description
1806           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1807           */
1808          filter: invokeLater('$filterProvider', 'register'),
1809
1810          /**
1811           * @ngdoc method
1812           * @name angular.Module#controller
1813           * @module ng
1814           * @param {string|Object} name Controller name, or an object map of controllers where the
1815           *    keys are the names and the values are the constructors.
1816           * @param {Function} constructor Controller constructor function.
1817           * @description
1818           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1819           */
1820          controller: invokeLater('$controllerProvider', 'register'),
1821
1822          /**
1823           * @ngdoc method
1824           * @name angular.Module#directive
1825           * @module ng
1826           * @param {string|Object} name Directive name, or an object map of directives where the
1827           *    keys are the names and the values are the factories.
1828           * @param {Function} directiveFactory Factory function for creating new instance of
1829           * directives.
1830           * @description
1831           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1832           */
1833          directive: invokeLater('$compileProvider', 'directive'),
1834
1835          /**
1836           * @ngdoc method
1837           * @name angular.Module#config
1838           * @module ng
1839           * @param {Function} configFn Execute this function on module load. Useful for service
1840           *    configuration.
1841           * @description
1842           * Use this method to register work which needs to be performed on module loading.
1843           * For more about how to configure services, see
1844           * {@link providers#providers_provider-recipe Provider Recipe}.
1845           */
1846          config: config,
1847
1848          /**
1849           * @ngdoc method
1850           * @name angular.Module#run
1851           * @module ng
1852           * @param {Function} initializationFn Execute this function after injector creation.
1853           *    Useful for application initialization.
1854           * @description
1855           * Use this method to register work which should be performed when the injector is done
1856           * loading all modules.
1857           */
1858          run: function(block) {
1859            runBlocks.push(block);
1860            return this;
1861          }
1862        };
1863
1864        if (configFn) {
1865          config(configFn);
1866        }
1867
1868        return  moduleInstance;
1869
1870        /**
1871         * @param {string} provider
1872         * @param {string} method
1873         * @param {String=} insertMethod
1874         * @returns {angular.Module}
1875         */
1876        function invokeLater(provider, method, insertMethod) {
1877          return function() {
1878            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1879            return moduleInstance;
1880          };
1881        }
1882      });
1883    };
1884  });
1885
1886}
1887
1888/* global angularModule: true,
1889  version: true,
1890
1891  $LocaleProvider,
1892  $CompileProvider,
1893
1894    htmlAnchorDirective,
1895    inputDirective,
1896    inputDirective,
1897    formDirective,
1898    scriptDirective,
1899    selectDirective,
1900    styleDirective,
1901    optionDirective,
1902    ngBindDirective,
1903    ngBindHtmlDirective,
1904    ngBindTemplateDirective,
1905    ngClassDirective,
1906    ngClassEvenDirective,
1907    ngClassOddDirective,
1908    ngCspDirective,
1909    ngCloakDirective,
1910    ngControllerDirective,
1911    ngFormDirective,
1912    ngHideDirective,
1913    ngIfDirective,
1914    ngIncludeDirective,
1915    ngIncludeFillContentDirective,
1916    ngInitDirective,
1917    ngNonBindableDirective,
1918    ngPluralizeDirective,
1919    ngRepeatDirective,
1920    ngShowDirective,
1921    ngStyleDirective,
1922    ngSwitchDirective,
1923    ngSwitchWhenDirective,
1924    ngSwitchDefaultDirective,
1925    ngOptionsDirective,
1926    ngTranscludeDirective,
1927    ngModelDirective,
1928    ngListDirective,
1929    ngChangeDirective,
1930    requiredDirective,
1931    requiredDirective,
1932    ngValueDirective,
1933    ngAttributeAliasDirectives,
1934    ngEventDirectives,
1935
1936    $AnchorScrollProvider,
1937    $AnimateProvider,
1938    $BrowserProvider,
1939    $CacheFactoryProvider,
1940    $ControllerProvider,
1941    $DocumentProvider,
1942    $ExceptionHandlerProvider,
1943    $FilterProvider,
1944    $InterpolateProvider,
1945    $IntervalProvider,
1946    $HttpProvider,
1947    $HttpBackendProvider,
1948    $LocationProvider,
1949    $LogProvider,
1950    $ParseProvider,
1951    $RootScopeProvider,
1952    $QProvider,
1953    $$SanitizeUriProvider,
1954    $SceProvider,
1955    $SceDelegateProvider,
1956    $SnifferProvider,
1957    $TemplateCacheProvider,
1958    $TimeoutProvider,
1959    $$RAFProvider,
1960    $$AsyncCallbackProvider,
1961    $WindowProvider
1962*/
1963
1964
1965/**
1966 * @ngdoc object
1967 * @name angular.version
1968 * @module ng
1969 * @description
1970 * An object that contains information about the current AngularJS version. This object has the
1971 * following properties:
1972 *
1973 * - `full` – `{string}` – Full version string, such as "0.9.18".
1974 * - `major` – `{number}` – Major version number, such as "0".
1975 * - `minor` – `{number}` – Minor version number, such as "9".
1976 * - `dot` – `{number}` – Dot version number, such as "18".
1977 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1978 */
1979var version = {
1980  full: '1.2.22',    // all of these placeholder strings will be replaced by grunt's
1981  major: 1,    // package task
1982  minor: 2,
1983  dot: 22,
1984  codeName: 'finicky-pleasure'
1985};
1986
1987
1988function publishExternalAPI(angular){
1989  extend(angular, {
1990    'bootstrap': bootstrap,
1991    'copy': copy,
1992    'extend': extend,
1993    'equals': equals,
1994    'element': jqLite,
1995    'forEach': forEach,
1996    'injector': createInjector,
1997    'noop': noop,
1998    'bind': bind,
1999    'toJson': toJson,
2000    'fromJson': fromJson,
2001    'identity': identity,
2002    'isUndefined': isUndefined,
2003    'isDefined': isDefined,
2004    'isString': isString,
2005    'isFunction': isFunction,
2006    'isObject': isObject,
2007    'isNumber': isNumber,
2008    'isElement': isElement,
2009    'isArray': isArray,
2010    'version': version,
2011    'isDate': isDate,
2012    'lowercase': lowercase,
2013    'uppercase': uppercase,
2014    'callbacks': {counter: 0},
2015    '$$minErr': minErr,
2016    '$$csp': csp
2017  });
2018
2019  angularModule = setupModuleLoader(window);
2020  try {
2021    angularModule('ngLocale');
2022  } catch (e) {
2023    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2024  }
2025
2026  angularModule('ng', ['ngLocale'], ['$provide',
2027    function ngModule($provide) {
2028      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2029      $provide.provider({
2030        $$sanitizeUri: $$SanitizeUriProvider
2031      });
2032      $provide.provider('$compile', $CompileProvider).
2033        directive({
2034            a: htmlAnchorDirective,
2035            input: inputDirective,
2036            textarea: inputDirective,
2037            form: formDirective,
2038            script: scriptDirective,
2039            select: selectDirective,
2040            style: styleDirective,
2041            option: optionDirective,
2042            ngBind: ngBindDirective,
2043            ngBindHtml: ngBindHtmlDirective,
2044            ngBindTemplate: ngBindTemplateDirective,
2045            ngClass: ngClassDirective,
2046            ngClassEven: ngClassEvenDirective,
2047            ngClassOdd: ngClassOddDirective,
2048            ngCloak: ngCloakDirective,
2049            ngController: ngControllerDirective,
2050            ngForm: ngFormDirective,
2051            ngHide: ngHideDirective,
2052            ngIf: ngIfDirective,
2053            ngInclude: ngIncludeDirective,
2054            ngInit: ngInitDirective,
2055            ngNonBindable: ngNonBindableDirective,
2056            ngPluralize: ngPluralizeDirective,
2057            ngRepeat: ngRepeatDirective,
2058            ngShow: ngShowDirective,
2059            ngStyle: ngStyleDirective,
2060            ngSwitch: ngSwitchDirective,
2061            ngSwitchWhen: ngSwitchWhenDirective,
2062            ngSwitchDefault: ngSwitchDefaultDirective,
2063            ngOptions: ngOptionsDirective,
2064            ngTransclude: ngTranscludeDirective,
2065            ngModel: ngModelDirective,
2066            ngList: ngListDirective,
2067            ngChange: ngChangeDirective,
2068            required: requiredDirective,
2069            ngRequired: requiredDirective,
2070            ngValue: ngValueDirective
2071        }).
2072        directive({
2073          ngInclude: ngIncludeFillContentDirective
2074        }).
2075        directive(ngAttributeAliasDirectives).
2076        directive(ngEventDirectives);
2077      $provide.provider({
2078        $anchorScroll: $AnchorScrollProvider,
2079        $animate: $AnimateProvider,
2080        $browser: $BrowserProvider,
2081        $cacheFactory: $CacheFactoryProvider,
2082        $controller: $ControllerProvider,
2083        $document: $DocumentProvider,
2084        $exceptionHandler: $ExceptionHandlerProvider,
2085        $filter: $FilterProvider,
2086        $interpolate: $InterpolateProvider,
2087        $interval: $IntervalProvider,
2088        $http: $HttpProvider,
2089        $httpBackend: $HttpBackendProvider,
2090        $location: $LocationProvider,
2091        $log: $LogProvider,
2092        $parse: $ParseProvider,
2093        $rootScope: $RootScopeProvider,
2094        $q: $QProvider,
2095        $sce: $SceProvider,
2096        $sceDelegate: $SceDelegateProvider,
2097        $sniffer: $SnifferProvider,
2098        $templateCache: $TemplateCacheProvider,
2099        $timeout: $TimeoutProvider,
2100        $window: $WindowProvider,
2101        $$rAF: $$RAFProvider,
2102        $$asyncCallback : $$AsyncCallbackProvider
2103      });
2104    }
2105  ]);
2106}
2107
2108/* global JQLitePrototype: true,
2109  addEventListenerFn: true,
2110  removeEventListenerFn: true,
2111  BOOLEAN_ATTR: true
2112*/
2113
2114//////////////////////////////////
2115//JQLite
2116//////////////////////////////////
2117
2118/**
2119 * @ngdoc function
2120 * @name angular.element
2121 * @module ng
2122 * @kind function
2123 *
2124 * @description
2125 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2126 *
2127 * If jQuery is available, `angular.element` is an alias for the
2128 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2129 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2130 *
2131 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2132 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2133 * commonly needed functionality with the goal of having a very small footprint.</div>
2134 *
2135 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2136 *
2137 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2138 * jqLite; they are never raw DOM references.</div>
2139 *
2140 * ## Angular's jqLite
2141 * jqLite provides only the following jQuery methods:
2142 *
2143 * - [`addClass()`](http://api.jquery.com/addClass/)
2144 * - [`after()`](http://api.jquery.com/after/)
2145 * - [`append()`](http://api.jquery.com/append/)
2146 * - [`attr()`](http://api.jquery.com/attr/)
2147 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2148 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2149 * - [`clone()`](http://api.jquery.com/clone/)
2150 * - [`contents()`](http://api.jquery.com/contents/)
2151 * - [`css()`](http://api.jquery.com/css/)
2152 * - [`data()`](http://api.jquery.com/data/)
2153 * - [`empty()`](http://api.jquery.com/empty/)
2154 * - [`eq()`](http://api.jquery.com/eq/)
2155 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2156 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2157 * - [`html()`](http://api.jquery.com/html/)
2158 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2159 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2160 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2161 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2162 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2163 * - [`prepend()`](http://api.jquery.com/prepend/)
2164 * - [`prop()`](http://api.jquery.com/prop/)
2165 * - [`ready()`](http://api.jquery.com/ready/)
2166 * - [`remove()`](http://api.jquery.com/remove/)
2167 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2168 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2169 * - [`removeData()`](http://api.jquery.com/removeData/)
2170 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2171 * - [`text()`](http://api.jquery.com/text/)
2172 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2173 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2174 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2175 * - [`val()`](http://api.jquery.com/val/)
2176 * - [`wrap()`](http://api.jquery.com/wrap/)
2177 *
2178 * ## jQuery/jqLite Extras
2179 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2180 *
2181 * ### Events
2182 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2183 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2184 *    element before it is removed.
2185 *
2186 * ### Methods
2187 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2188 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2189 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2190 *   `'ngModel'`).
2191 * - `injector()` - retrieves the injector of the current element or its parent.
2192 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2193 *   element or its parent.
2194 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2195 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2196 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2197 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2198 *   parent element is reached.
2199 *
2200 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2201 * @returns {Object} jQuery object.
2202 */
2203
2204JQLite.expando = 'ng339';
2205
2206var jqCache = JQLite.cache = {},
2207    jqId = 1,
2208    addEventListenerFn = (window.document.addEventListener
2209      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2210      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2211    removeEventListenerFn = (window.document.removeEventListener
2212      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2213      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2214
2215/*
2216 * !!! This is an undocumented "private" function !!!
2217 */
2218var jqData = JQLite._data = function(node) {
2219  //jQuery always returns an object on cache miss
2220  return this.cache[node[this.expando]] || {};
2221};
2222
2223function jqNextId() { return ++jqId; }
2224
2225
2226var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2227var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2228var jqLiteMinErr = minErr('jqLite');
2229
2230/**
2231 * Converts snake_case to camelCase.
2232 * Also there is special case for Moz prefix starting with upper case letter.
2233 * @param name Name to normalize
2234 */
2235function camelCase(name) {
2236  return name.
2237    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2238      return offset ? letter.toUpperCase() : letter;
2239    }).
2240    replace(MOZ_HACK_REGEXP, 'Moz$1');
2241}
2242
2243/////////////////////////////////////////////
2244// jQuery mutation patch
2245//
2246// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2247// $destroy event on all DOM nodes being removed.
2248//
2249/////////////////////////////////////////////
2250
2251function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2252  var originalJqFn = jQuery.fn[name];
2253  originalJqFn = originalJqFn.$original || originalJqFn;
2254  removePatch.$original = originalJqFn;
2255  jQuery.fn[name] = removePatch;
2256
2257  function removePatch(param) {
2258    // jshint -W040
2259    var list = filterElems && param ? [this.filter(param)] : [this],
2260        fireEvent = dispatchThis,
2261        set, setIndex, setLength,
2262        element, childIndex, childLength, children;
2263
2264    if (!getterIfNoArguments || param != null) {
2265      while(list.length) {
2266        set = list.shift();
2267        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2268          element = jqLite(set[setIndex]);
2269          if (fireEvent) {
2270            element.triggerHandler('$destroy');
2271          } else {
2272            fireEvent = !fireEvent;
2273          }
2274          for(childIndex = 0, childLength = (children = element.children()).length;
2275              childIndex < childLength;
2276              childIndex++) {
2277            list.push(jQuery(children[childIndex]));
2278          }
2279        }
2280      }
2281    }
2282    return originalJqFn.apply(this, arguments);
2283  }
2284}
2285
2286var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2287var HTML_REGEXP = /<|&#?\w+;/;
2288var TAG_NAME_REGEXP = /<([\w:]+)/;
2289var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2290
2291var wrapMap = {
2292  'option': [1, '<select multiple="multiple">', '</select>'],
2293
2294  'thead': [1, '<table>', '</table>'],
2295  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2296  'tr': [2, '<table><tbody>', '</tbody></table>'],
2297  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2298  '_default': [0, "", ""]
2299};
2300
2301wrapMap.optgroup = wrapMap.option;
2302wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2303wrapMap.th = wrapMap.td;
2304
2305function jqLiteIsTextNode(html) {
2306  return !HTML_REGEXP.test(html);
2307}
2308
2309function jqLiteBuildFragment(html, context) {
2310  var elem, tmp, tag, wrap,
2311      fragment = context.createDocumentFragment(),
2312      nodes = [], i, j, jj;
2313
2314  if (jqLiteIsTextNode(html)) {
2315    // Convert non-html into a text node
2316    nodes.push(context.createTextNode(html));
2317  } else {
2318    tmp = fragment.appendChild(context.createElement('div'));
2319    // Convert html into DOM nodes
2320    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2321    wrap = wrapMap[tag] || wrapMap._default;
2322    tmp.innerHTML = '<div>&#160;</div>' +
2323      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2324    tmp.removeChild(tmp.firstChild);
2325
2326    // Descend through wrappers to the right content
2327    i = wrap[0];
2328    while (i--) {
2329      tmp = tmp.lastChild;
2330    }
2331
2332    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
2333
2334    tmp = fragment.firstChild;
2335    tmp.textContent = "";
2336  }
2337
2338  // Remove wrapper from fragment
2339  fragment.textContent = "";
2340  fragment.innerHTML = ""; // Clear inner HTML
2341  return nodes;
2342}
2343
2344function jqLiteParseHTML(html, context) {
2345  context = context || document;
2346  var parsed;
2347
2348  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2349    return [context.createElement(parsed[1])];
2350  }
2351
2352  return jqLiteBuildFragment(html, context);
2353}
2354
2355/////////////////////////////////////////////
2356function JQLite(element) {
2357  if (element instanceof JQLite) {
2358    return element;
2359  }
2360  if (isString(element)) {
2361    element = trim(element);
2362  }
2363  if (!(this instanceof JQLite)) {
2364    if (isString(element) && element.charAt(0) != '<') {
2365      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2366    }
2367    return new JQLite(element);
2368  }
2369
2370  if (isString(element)) {
2371    jqLiteAddNodes(this, jqLiteParseHTML(element));
2372    var fragment = jqLite(document.createDocumentFragment());
2373    fragment.append(this);
2374  } else {
2375    jqLiteAddNodes(this, element);
2376  }
2377}
2378
2379function jqLiteClone(element) {
2380  return element.cloneNode(true);
2381}
2382
2383function jqLiteDealoc(element){
2384  jqLiteRemoveData(element);
2385  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2386    jqLiteDealoc(children[i]);
2387  }
2388}
2389
2390function jqLiteOff(element, type, fn, unsupported) {
2391  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2392
2393  var events = jqLiteExpandoStore(element, 'events'),
2394      handle = jqLiteExpandoStore(element, 'handle');
2395
2396  if (!handle) return; //no listeners registered
2397
2398  if (isUndefined(type)) {
2399    forEach(events, function(eventHandler, type) {
2400      removeEventListenerFn(element, type, eventHandler);
2401      delete events[type];
2402    });
2403  } else {
2404    forEach(type.split(' '), function(type) {
2405      if (isUndefined(fn)) {
2406        removeEventListenerFn(element, type, events[type]);
2407        delete events[type];
2408      } else {
2409        arrayRemove(events[type] || [], fn);
2410      }
2411    });
2412  }
2413}
2414
2415function jqLiteRemoveData(element, name) {
2416  var expandoId = element.ng339,
2417      expandoStore = jqCache[expandoId];
2418
2419  if (expandoStore) {
2420    if (name) {
2421      delete jqCache[expandoId].data[name];
2422      return;
2423    }
2424
2425    if (expandoStore.handle) {
2426      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2427      jqLiteOff(element);
2428    }
2429    delete jqCache[expandoId];
2430    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2431  }
2432}
2433
2434function jqLiteExpandoStore(element, key, value) {
2435  var expandoId = element.ng339,
2436      expandoStore = jqCache[expandoId || -1];
2437
2438  if (isDefined(value)) {
2439    if (!expandoStore) {
2440      element.ng339 = expandoId = jqNextId();
2441      expandoStore = jqCache[expandoId] = {};
2442    }
2443    expandoStore[key] = value;
2444  } else {
2445    return expandoStore && expandoStore[key];
2446  }
2447}
2448
2449function jqLiteData(element, key, value) {
2450  var data = jqLiteExpandoStore(element, 'data'),
2451      isSetter = isDefined(value),
2452      keyDefined = !isSetter && isDefined(key),
2453      isSimpleGetter = keyDefined && !isObject(key);
2454
2455  if (!data && !isSimpleGetter) {
2456    jqLiteExpandoStore(element, 'data', data = {});
2457  }
2458
2459  if (isSetter) {
2460    data[key] = value;
2461  } else {
2462    if (keyDefined) {
2463      if (isSimpleGetter) {
2464        // don't create data in this case.
2465        return data && data[key];
2466      } else {
2467        extend(data, key);
2468      }
2469    } else {
2470      return data;
2471    }
2472  }
2473}
2474
2475function jqLiteHasClass(element, selector) {
2476  if (!element.getAttribute) return false;
2477  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2478      indexOf( " " + selector + " " ) > -1);
2479}
2480
2481function jqLiteRemoveClass(element, cssClasses) {
2482  if (cssClasses && element.setAttribute) {
2483    forEach(cssClasses.split(' '), function(cssClass) {
2484      element.setAttribute('class', trim(
2485          (" " + (element.getAttribute('class') || '') + " ")
2486          .replace(/[\n\t]/g, " ")
2487          .replace(" " + trim(cssClass) + " ", " "))
2488      );
2489    });
2490  }
2491}
2492
2493function jqLiteAddClass(element, cssClasses) {
2494  if (cssClasses && element.setAttribute) {
2495    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2496                            .replace(/[\n\t]/g, " ");
2497
2498    forEach(cssClasses.split(' '), function(cssClass) {
2499      cssClass = trim(cssClass);
2500      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2501        existingClasses += cssClass + ' ';
2502      }
2503    });
2504
2505    element.setAttribute('class', trim(existingClasses));
2506  }
2507}
2508
2509function jqLiteAddNodes(root, elements) {
2510  if (elements) {
2511    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2512      ? elements
2513      : [ elements ];
2514    for(var i=0; i < elements.length; i++) {
2515      root.push(elements[i]);
2516    }
2517  }
2518}
2519
2520function jqLiteController(element, name) {
2521  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2522}
2523
2524function jqLiteInheritedData(element, name, value) {
2525  // if element is the document object work with the html element instead
2526  // this makes $(document).scope() possible
2527  if(element.nodeType == 9) {
2528    element = element.documentElement;
2529  }
2530  var names = isArray(name) ? name : [name];
2531
2532  while (element) {
2533    for (var i = 0, ii = names.length; i < ii; i++) {
2534      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2535    }
2536
2537    // If dealing with a document fragment node with a host element, and no parent, use the host
2538    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2539    // to lookup parent controllers.
2540    element = element.parentNode || (element.nodeType === 11 && element.host);
2541  }
2542}
2543
2544function jqLiteEmpty(element) {
2545  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2546    jqLiteDealoc(childNodes[i]);
2547  }
2548  while (element.firstChild) {
2549    element.removeChild(element.firstChild);
2550  }
2551}
2552
2553//////////////////////////////////////////
2554// Functions which are declared directly.
2555//////////////////////////////////////////
2556var JQLitePrototype = JQLite.prototype = {
2557  ready: function(fn) {
2558    var fired = false;
2559
2560    function trigger() {
2561      if (fired) return;
2562      fired = true;
2563      fn();
2564    }
2565
2566    // check if document already is loaded
2567    if (document.readyState === 'complete'){
2568      setTimeout(trigger);
2569    } else {
2570      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2571      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2572      // jshint -W064
2573      JQLite(window).on('load', trigger); // fallback to window.onload for others
2574      // jshint +W064
2575    }
2576  },
2577  toString: function() {
2578    var value = [];
2579    forEach(this, function(e){ value.push('' + e);});
2580    return '[' + value.join(', ') + ']';
2581  },
2582
2583  eq: function(index) {
2584      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2585  },
2586
2587  length: 0,
2588  push: push,
2589  sort: [].sort,
2590  splice: [].splice
2591};
2592
2593//////////////////////////////////////////
2594// Functions iterating getter/setters.
2595// these functions return self on setter and
2596// value on get.
2597//////////////////////////////////////////
2598var BOOLEAN_ATTR = {};
2599forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2600  BOOLEAN_ATTR[lowercase(value)] = value;
2601});
2602var BOOLEAN_ELEMENTS = {};
2603forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2604  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2605});
2606
2607function getBooleanAttrName(element, name) {
2608  // check dom last since we will most likely fail on name
2609  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2610
2611  // booleanAttr is here twice to minimize DOM access
2612  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2613}
2614
2615forEach({
2616  data: jqLiteData,
2617  removeData: jqLiteRemoveData
2618}, function(fn, name) {
2619  JQLite[name] = fn;
2620});
2621
2622forEach({
2623  data: jqLiteData,
2624  inheritedData: jqLiteInheritedData,
2625
2626  scope: function(element) {
2627    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2628    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2629  },
2630
2631  isolateScope: function(element) {
2632    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2633    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2634  },
2635
2636  controller: jqLiteController,
2637
2638  injector: function(element) {
2639    return jqLiteInheritedData(element, '$injector');
2640  },
2641
2642  removeAttr: function(element,name) {
2643    element.removeAttribute(name);
2644  },
2645
2646  hasClass: jqLiteHasClass,
2647
2648  css: function(element, name, value) {
2649    name = camelCase(name);
2650
2651    if (isDefined(value)) {
2652      element.style[name] = value;
2653    } else {
2654      var val;
2655
2656      if (msie <= 8) {
2657        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2658        val = element.currentStyle && element.currentStyle[name];
2659        if (val === '') val = 'auto';
2660      }
2661
2662      val = val || element.style[name];
2663
2664      if (msie <= 8) {
2665        // jquery weirdness :-/
2666        val = (val === '') ? undefined : val;
2667      }
2668
2669      return  val;
2670    }
2671  },
2672
2673  attr: function(element, name, value){
2674    var lowercasedName = lowercase(name);
2675    if (BOOLEAN_ATTR[lowercasedName]) {
2676      if (isDefined(value)) {
2677        if (!!value) {
2678          element[name] = true;
2679          element.setAttribute(name, lowercasedName);
2680        } else {
2681          element[name] = false;
2682          element.removeAttribute(lowercasedName);
2683        }
2684      } else {
2685        return (element[name] ||
2686                 (element.attributes.getNamedItem(name)|| noop).specified)
2687               ? lowercasedName
2688               : undefined;
2689      }
2690    } else if (isDefined(value)) {
2691      element.setAttribute(name, value);
2692    } else if (element.getAttribute) {
2693      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2694      // some elements (e.g. Document) don't have get attribute, so return undefined
2695      var ret = element.getAttribute(name, 2);
2696      // normalize non-existing attributes to undefined (as jQuery)
2697      return ret === null ? undefined : ret;
2698    }
2699  },
2700
2701  prop: function(element, name, value) {
2702    if (isDefined(value)) {
2703      element[name] = value;
2704    } else {
2705      return element[name];
2706    }
2707  },
2708
2709  text: (function() {
2710    var NODE_TYPE_TEXT_PROPERTY = [];
2711    if (msie < 9) {
2712      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2713      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2714    } else {
2715      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2716      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2717    }
2718    getText.$dv = '';
2719    return getText;
2720
2721    function getText(element, value) {
2722      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2723      if (isUndefined(value)) {
2724        return textProp ? element[textProp] : '';
2725      }
2726      element[textProp] = value;
2727    }
2728  })(),
2729
2730  val: function(element, value) {
2731    if (isUndefined(value)) {
2732      if (nodeName_(element) === 'SELECT' && element.multiple) {
2733        var result = [];
2734        forEach(element.options, function (option) {
2735          if (option.selected) {
2736            result.push(option.value || option.text);
2737          }
2738        });
2739        return result.length === 0 ? null : result;
2740      }
2741      return element.value;
2742    }
2743    element.value = value;
2744  },
2745
2746  html: function(element, value) {
2747    if (isUndefined(value)) {
2748      return element.innerHTML;
2749    }
2750    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2751      jqLiteDealoc(childNodes[i]);
2752    }
2753    element.innerHTML = value;
2754  },
2755
2756  empty: jqLiteEmpty
2757}, function(fn, name){
2758  /**
2759   * Properties: writes return selection, reads return first value
2760   */
2761  JQLite.prototype[name] = function(arg1, arg2) {
2762    var i, key;
2763    var nodeCount = this.length;
2764
2765    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2766    // in a way that survives minification.
2767    // jqLiteEmpty takes no arguments but is a setter.
2768    if (fn !== jqLiteEmpty &&
2769        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2770      if (isObject(arg1)) {
2771
2772        // we are a write, but the object properties are the key/values
2773        for (i = 0; i < nodeCount; i++) {
2774          if (fn === jqLiteData) {
2775            // data() takes the whole object in jQuery
2776            fn(this[i], arg1);
2777          } else {
2778            for (key in arg1) {
2779              fn(this[i], key, arg1[key]);
2780            }
2781          }
2782        }
2783        // return self for chaining
2784        return this;
2785      } else {
2786        // we are a read, so read the first child.
2787        // TODO: do we still need this?
2788        var value = fn.$dv;
2789        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2790        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2791        for (var j = 0; j < jj; j++) {
2792          var nodeValue = fn(this[j], arg1, arg2);
2793          value = value ? value + nodeValue : nodeValue;
2794        }
2795        return value;
2796      }
2797    } else {
2798      // we are a write, so apply to all children
2799      for (i = 0; i < nodeCount; i++) {
2800        fn(this[i], arg1, arg2);
2801      }
2802      // return self for chaining
2803      return this;
2804    }
2805  };
2806});
2807
2808function createEventHandler(element, events) {
2809  var eventHandler = function (event, type) {
2810    if (!event.preventDefault) {
2811      event.preventDefault = function() {
2812        event.returnValue = false; //ie
2813      };
2814    }
2815
2816    if (!event.stopPropagation) {
2817      event.stopPropagation = function() {
2818        event.cancelBubble = true; //ie
2819      };
2820    }
2821
2822    if (!event.target) {
2823      event.target = event.srcElement || document;
2824    }
2825
2826    if (isUndefined(event.defaultPrevented)) {
2827      var prevent = event.preventDefault;
2828      event.preventDefault = function() {
2829        event.defaultPrevented = true;
2830        prevent.call(event);
2831      };
2832      event.defaultPrevented = false;
2833    }
2834
2835    event.isDefaultPrevented = function() {
2836      return event.defaultPrevented || event.returnValue === false;
2837    };
2838
2839    // Copy event handlers in case event handlers array is modified during execution.
2840    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2841
2842    forEach(eventHandlersCopy, function(fn) {
2843      fn.call(element, event);
2844    });
2845
2846    // Remove monkey-patched methods (IE),
2847    // as they would cause memory leaks in IE8.
2848    if (msie <= 8) {
2849      // IE7/8 does not allow to delete property on native object
2850      event.preventDefault = null;
2851      event.stopPropagation = null;
2852      event.isDefaultPrevented = null;
2853    } else {
2854      // It shouldn't affect normal browsers (native methods are defined on prototype).
2855      delete event.preventDefault;
2856      delete event.stopPropagation;
2857      delete event.isDefaultPrevented;
2858    }
2859  };
2860  eventHandler.elem = element;
2861  return eventHandler;
2862}
2863
2864//////////////////////////////////////////
2865// Functions iterating traversal.
2866// These functions chain results into a single
2867// selector.
2868//////////////////////////////////////////
2869forEach({
2870  removeData: jqLiteRemoveData,
2871
2872  dealoc: jqLiteDealoc,
2873
2874  on: function onFn(element, type, fn, unsupported){
2875    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2876
2877    var events = jqLiteExpandoStore(element, 'events'),
2878        handle = jqLiteExpandoStore(element, 'handle');
2879
2880    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2881    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2882
2883    forEach(type.split(' '), function(type){
2884      var eventFns = events[type];
2885
2886      if (!eventFns) {
2887        if (type == 'mouseenter' || type == 'mouseleave') {
2888          var contains = document.body.contains || document.body.compareDocumentPosition ?
2889          function( a, b ) {
2890            // jshint bitwise: false
2891            var adown = a.nodeType === 9 ? a.documentElement : a,
2892            bup = b && b.parentNode;
2893            return a === bup || !!( bup && bup.nodeType === 1 && (
2894              adown.contains ?
2895              adown.contains( bup ) :
2896              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2897              ));
2898            } :
2899            function( a, b ) {
2900              if ( b ) {
2901                while ( (b = b.parentNode) ) {
2902                  if ( b === a ) {
2903                    return true;
2904                  }
2905                }
2906              }
2907              return false;
2908            };
2909
2910          events[type] = [];
2911
2912          // Refer to jQuery's implementation of mouseenter & mouseleave
2913          // Read about mouseenter and mouseleave:
2914          // http://www.quirksmode.org/js/events_mouse.html#link8
2915          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2916
2917          onFn(element, eventmap[type], function(event) {
2918            var target = this, related = event.relatedTarget;
2919            // For mousenter/leave call the handler if related is outside the target.
2920            // NB: No relatedTarget if the mouse left/entered the browser window
2921            if ( !related || (related !== target && !contains(target, related)) ){
2922              handle(event, type);
2923            }
2924          });
2925
2926        } else {
2927          addEventListenerFn(element, type, handle);
2928          events[type] = [];
2929        }
2930        eventFns = events[type];
2931      }
2932      eventFns.push(fn);
2933    });
2934  },
2935
2936  off: jqLiteOff,
2937
2938  one: function(element, type, fn) {
2939    element = jqLite(element);
2940
2941    //add the listener twice so that when it is called
2942    //you can remove the original function and still be
2943    //able to call element.off(ev, fn) normally
2944    element.on(type, function onFn() {
2945      element.off(type, fn);
2946      element.off(type, onFn);
2947    });
2948    element.on(type, fn);
2949  },
2950
2951  replaceWith: function(element, replaceNode) {
2952    var index, parent = element.parentNode;
2953    jqLiteDealoc(element);
2954    forEach(new JQLite(replaceNode), function(node){
2955      if (index) {
2956        parent.insertBefore(node, index.nextSibling);
2957      } else {
2958        parent.replaceChild(node, element);
2959      }
2960      index = node;
2961    });
2962  },
2963
2964  children: function(element) {
2965    var children = [];
2966    forEach(element.childNodes, function(element){
2967      if (element.nodeType === 1)
2968        children.push(element);
2969    });
2970    return children;
2971  },
2972
2973  contents: function(element) {
2974    return element.contentDocument || element.childNodes || [];
2975  },
2976
2977  append: function(element, node) {
2978    forEach(new JQLite(node), function(child){
2979      if (element.nodeType === 1 || element.nodeType === 11) {
2980        element.appendChild(child);
2981      }
2982    });
2983  },
2984
2985  prepend: function(element, node) {
2986    if (element.nodeType === 1) {
2987      var index = element.firstChild;
2988      forEach(new JQLite(node), function(child){
2989        element.insertBefore(child, index);
2990      });
2991    }
2992  },
2993
2994  wrap: function(element, wrapNode) {
2995    wrapNode = jqLite(wrapNode)[0];
2996    var parent = element.parentNode;
2997    if (parent) {
2998      parent.replaceChild(wrapNode, element);
2999    }
3000    wrapNode.appendChild(element);
3001  },
3002
3003  remove: function(element) {
3004    jqLiteDealoc(element);
3005    var parent = element.parentNode;
3006    if (parent) parent.removeChild(element);
3007  },
3008
3009  after: function(element, newElement) {
3010    var index = element, parent = element.parentNode;
3011    forEach(new JQLite(newElement), function(node){
3012      parent.insertBefore(node, index.nextSibling);
3013      index = node;
3014    });
3015  },
3016
3017  addClass: jqLiteAddClass,
3018  removeClass: jqLiteRemoveClass,
3019
3020  toggleClass: function(element, selector, condition) {
3021    if (selector) {
3022      forEach(selector.split(' '), function(className){
3023        var classCondition = condition;
3024        if (isUndefined(classCondition)) {
3025          classCondition = !jqLiteHasClass(element, className);
3026        }
3027        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3028      });
3029    }
3030  },
3031
3032  parent: function(element) {
3033    var parent = element.parentNode;
3034    return parent && parent.nodeType !== 11 ? parent : null;
3035  },
3036
3037  next: function(element) {
3038    if (element.nextElementSibling) {
3039      return element.nextElementSibling;
3040    }
3041
3042    // IE8 doesn't have nextElementSibling
3043    var elm = element.nextSibling;
3044    while (elm != null && elm.nodeType !== 1) {
3045      elm = elm.nextSibling;
3046    }
3047    return elm;
3048  },
3049
3050  find: function(element, selector) {
3051    if (element.getElementsByTagName) {
3052      return element.getElementsByTagName(selector);
3053    } else {
3054      return [];
3055    }
3056  },
3057
3058  clone: jqLiteClone,
3059
3060  triggerHandler: function(element, event, extraParameters) {
3061
3062    var dummyEvent, eventFnsCopy, handlerArgs;
3063    var eventName = event.type || event;
3064    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
3065
3066    if (eventFns) {
3067
3068      // Create a dummy event to pass to the handlers
3069      dummyEvent = {
3070        preventDefault: function() { this.defaultPrevented = true; },
3071        isDefaultPrevented: function() { return this.defaultPrevented === true; },
3072        stopPropagation: noop,
3073        type: eventName,
3074        target: element
3075      };
3076
3077      // If a custom event was provided then extend our dummy event with it
3078      if (event.type) {
3079        dummyEvent = extend(dummyEvent, event);
3080      }
3081
3082      // Copy event handlers in case event handlers array is modified during execution.
3083      eventFnsCopy = shallowCopy(eventFns);
3084      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3085
3086      forEach(eventFnsCopy, function(fn) {
3087        fn.apply(element, handlerArgs);
3088      });
3089
3090    }
3091  }
3092}, function(fn, name){
3093  /**
3094   * chaining functions
3095   */
3096  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3097    var value;
3098    for(var i=0; i < this.length; i++) {
3099      if (isUndefined(value)) {
3100        value = fn(this[i], arg1, arg2, arg3);
3101        if (isDefined(value)) {
3102          // any function which returns a value needs to be wrapped
3103          value = jqLite(value);
3104        }
3105      } else {
3106        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3107      }
3108    }
3109    return isDefined(value) ? value : this;
3110  };
3111
3112  // bind legacy bind/unbind to on/off
3113  JQLite.prototype.bind = JQLite.prototype.on;
3114  JQLite.prototype.unbind = JQLite.prototype.off;
3115});
3116
3117/**
3118 * Computes a hash of an 'obj'.
3119 * Hash of a:
3120 *  string is string
3121 *  number is number as string
3122 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3123 *         that is also assigned to the $$hashKey property of the object.
3124 *
3125 * @param obj
3126 * @returns {string} hash string such that the same input will have the same hash string.
3127 *         The resulting string key is in 'type:hashKey' format.
3128 */
3129function hashKey(obj, nextUidFn) {
3130  var objType = typeof obj,
3131      key;
3132
3133  if (objType == 'function' || (objType == 'object' && obj !== null)) {
3134    if (typeof (key = obj.$$hashKey) == 'function') {
3135      // must invoke on object to keep the right this
3136      key = obj.$$hashKey();
3137    } else if (key === undefined) {
3138      key = obj.$$hashKey = (nextUidFn || nextUid)();
3139    }
3140  } else {
3141    key = obj;
3142  }
3143
3144  return objType + ':' + key;
3145}
3146
3147/**
3148 * HashMap which can use objects as keys
3149 */
3150function HashMap(array, isolatedUid) {
3151  if (isolatedUid) {
3152    var uid = 0;
3153    this.nextUid = function() {
3154      return ++uid;
3155    };
3156  }
3157  forEach(array, this.put, this);
3158}
3159HashMap.prototype = {
3160  /**
3161   * Store key value pair
3162   * @param key key to store can be any type
3163   * @param value value to store can be any type
3164   */
3165  put: function(key, value) {
3166    this[hashKey(key, this.nextUid)] = value;
3167  },
3168
3169  /**
3170   * @param key
3171   * @returns {Object} the value for the key
3172   */
3173  get: function(key) {
3174    return this[hashKey(key, this.nextUid)];
3175  },
3176
3177  /**
3178   * Remove the key/value pair
3179   * @param key
3180   */
3181  remove: function(key) {
3182    var value = this[key = hashKey(key, this.nextUid)];
3183    delete this[key];
3184    return value;
3185  }
3186};
3187
3188/**
3189 * @ngdoc function
3190 * @module ng
3191 * @name angular.injector
3192 * @kind function
3193 *
3194 * @description
3195 * Creates an injector function that can be used for retrieving services as well as for
3196 * dependency injection (see {@link guide/di dependency injection}).
3197 *
3198
3199 * @param {Array.<string|Function>}
3199 modules A list of module functions or their aliases. See
3200 *        {@link angular.module}. The `ng` module must be explicitly added.
3201 * @returns {function()} Injector function. See {@link auto.$injector $injector}.
3202 *
3203 * @example
3204 * Typical usage
3205 * ```js
3206 *   // create an injector
3207 *   var $injector = angular.injector(['ng']);
3208 *
3209 *   // use the injector to kick off your application
3210 *   // use the type inference to auto inject arguments, or use implicit injection
3211 *   $injector.invoke(function($rootScope, $compile, $document){
3212 *     $compile($document)($rootScope);
3213 *     $rootScope.$digest();
3214 *   });
3215 * ```
3216 *
3217 * Sometimes you want to get access to the injector of a currently running Angular app
3218 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3219 * application has been bootstrapped. You can do this using the extra `injector()` added
3220 * to JQuery/jqLite elements. See {@link angular.element}.
3221 *
3222 * *This is fairly rare but could be the case if a third party library is injecting the
3223 * markup.*
3224 *
3225 * In the following example a new block of HTML containing a `ng-controller`
3226 * directive is added to the end of the document body by JQuery. We then compile and link
3227 * it into the current AngularJS scope.
3228 *
3229 * ```js
3230 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3231 * $(document.body).append($div);
3232 *
3233 * angular.element(document).injector().invoke(function($compile) {
3234 *   var scope = angular.element($div).scope();
3235 *   $compile($div)(scope);
3236 * });
3237 * ```
3238 */
3239
3240
3241/**
3242 * @ngdoc module
3243 * @name auto
3244 * @description
3245 *
3246 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3247 */
3248
3249var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3250var FN_ARG_SPLIT = /,/;
3251var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3252var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3253var $injectorMinErr = minErr('$injector');
3254function annotate(fn) {
3255  var $inject,
3256      fnText,
3257      argDecl,
3258      last;
3259
3260  if (typeof fn === 'function') {
3261    if (!($inject = fn.$inject)) {
3262      $inject = [];
3263      if (fn.length) {
3264        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3265        argDecl = fnText.match(FN_ARGS);
3266        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3267          arg.replace(FN_ARG, function(all, underscore, name){
3268            $inject.push(name);
3269          });
3270        });
3271      }
3272      fn.$inject = $inject;
3273    }
3274  } else if (isArray(fn)) {
3275    last = fn.length - 1;
3276    assertArgFn(fn[last], 'fn');
3277    $inject = fn.slice(0, last);
3278  } else {
3279    assertArgFn(fn, 'fn', true);
3280  }
3281  return $inject;
3282}
3283
3284///////////////////////////////////////
3285
3286/**
3287 * @ngdoc service
3288 * @name $injector
3289 * @kind function
3290 *
3291 * @description
3292 *
3293 * `$injector` is used to retrieve object instances as defined by
3294 * {@link auto.$provide provider}, instantiate types, invoke methods,
3295 * and load modules.
3296 *
3297 * The following always holds true:
3298 *
3299 * ```js
3300 *   var $injector = angular.injector();
3301 *   expect($injector.get('$injector')).toBe($injector);
3302 *   expect($injector.invoke(function($injector){
3303 *     return $injector;
3304 *   }).toBe($injector);
3305 * ```
3306 *
3307 * # Injection Function Annotation
3308 *
3309 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3310 * following are all valid ways of annotating function with injection arguments and are equivalent.
3311 *
3312 * ```js
3313 *   // inferred (only works if code not minified/obfuscated)
3314 *   $injector.invoke(function(serviceA){});
3315 *
3316 *   // annotated
3317 *   function explicit(serviceA) {};
3318 *   explicit.$inject = ['serviceA'];
3319 *   $injector.invoke(explicit);
3320 *
3321 *   // inline
3322 *   $injector.invoke(['serviceA', function(serviceA){}]);
3323 * ```
3324 *
3325 * ## Inference
3326 *
3327 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3328 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3329 * minification, and obfuscation tools since these tools change the argument names.
3330 *
3331 * ## `$inject` Annotation
3332 * By adding an `$inject` property onto a function the injection parameters can be specified.
3333 *
3334 * ## Inline
3335 * As an array of injection names, where the last item in the array is the function to call.
3336 */
3337
3338/**
3339 * @ngdoc method
3340 * @name $injector#get
3341 *
3342 * @description
3343 * Return an instance of the service.
3344 *
3345 * @param {string} name The name of the instance to retrieve.
3346 * @return {*} The instance.
3347 */
3348
3349/**
3350 * @ngdoc method
3351 * @name $injector#invoke
3352 *
3353 * @description
3354 * Invoke the method and supply the method arguments from the `$injector`.
3355 *
3356 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3357 *   {@link guide/di $inject Annotation} rules.
3358 * @param {Object=} self The `this` for the invoked method.
3359 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3360 *                         object first, before the `$injector` is consulted.
3361 * @returns {*} the value returned by the invoked `fn` function.
3362 */
3363
3364/**
3365 * @ngdoc method
3366 * @name $injector#has
3367 *
3368 * @description
3369 * Allows the user to query if the particular service exists.
3370 *
3371 * @param {string} Name of the service to query.
3372 * @returns {boolean} returns true if injector has given service.
3373 */
3374
3375/**
3376 * @ngdoc method
3377 * @name $injector#instantiate
3378 * @description
3379 * Create a new instance of JS type. The method takes a constructor function, invokes the new
3380 * operator, and supplies all of the arguments to the constructor function as specified by the
3381 * constructor annotation.
3382 *
3383 * @param {Function} Type Annotated constructor function.
3384 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3385 * object first, before the `$injector` is consulted.
3386 * @returns {Object} new instance of `Type`.
3387 */
3388
3389/**
3390 * @ngdoc method
3391 * @name $injector#annotate
3392 *
3393 * @description
3394 * Returns an array of service names which the function is requesting for injection. This API is
3395 * used by the injector to determine which services need to be injected into the function when the
3396 * function is invoked. There are three ways in which the function can be annotated with the needed
3397 * dependencies.
3398 *
3399 * # Argument names
3400 *
3401 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3402 * by converting the function into a string using `toString()` method and extracting the argument
3403 * names.
3404 * ```js
3405 *   // Given
3406 *   function MyController($scope, $route) {
3407 *     // ...
3408 *   }
3409 *
3410 *   // Then
3411 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3412 * ```
3413 *
3414 * This method does not work with code minification / obfuscation. For this reason the following
3415 * annotation strategies are supported.
3416 *
3417 * # The `$inject` property
3418 *
3419 * If a function has an `$inject` property and its value is an array of strings, then the strings
3420 * represent names of services to be injected into the function.
3421 * ```js
3422 *   // Given
3423 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3424 *     // ...
3425 *   }
3426 *   // Define function dependencies
3427 *   MyController['$inject'] = ['$scope', '$route'];
3428 *
3429 *   // Then
3430 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3431 * ```
3432 *
3433 * # The array notation
3434 *
3435 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3436 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3437 * a way that survives minification is a better choice:
3438 *
3439 * ```js
3440 *   // We wish to write this (not minification / obfuscation safe)
3441 *   injector.invoke(function($compile, $rootScope) {
3442 *     // ...
3443 *   });
3444 *
3445 *   // We are forced to write break inlining
3446 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3447 *     // ...
3448 *   };
3449 *   tmpFn.$inject = ['$compile', '$rootScope'];
3450 *   injector.invoke(tmpFn);
3451 *
3452 *   // To better support inline function the inline annotation is supported
3453 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3454 *     // ...
3455 *   }]);
3456 *
3457 *   // Therefore
3458 *   expect(injector.annotate(
3459 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3460 *    ).toEqual(['$compile', '$rootScope']);
3461 * ```
3462 *
3463 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3464 * be retrieved as described above.
3465 *
3466 * @returns {Array.<string>} The names of the services which the function requires.
3467 */
3468
3469
3470
3471
3472/**
3473 * @ngdoc service
3474 * @name $provide
3475 *
3476 * @description
3477 *
3478 * The {@link auto.$provide $provide} service has a number of methods for registering components
3479 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3480 * {@link angular.Module}.
3481 *
3482 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3483 * factories** are functions which, in turn, are created by a **service provider**.
3484 * The **service providers** are constructor functions. When instantiated they must contain a
3485 * property called `$get`, which holds the **service factory** function.
3486 *
3487 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3488 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3489 * function to get the instance of the **service**.
3490 *
3491 * Often services have no configuration options and there is no need to add methods to the service
3492 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3493 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3494 * services without specifying a provider.
3495 *
3496 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3497 *     {@link auto.$injector $injector}
3498 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3499 *     providers and services.
3500 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3501 *     services, not providers.
3502 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3503 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3504 *     given factory function.
3505 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3506 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3507 *      a new object using the given constructor function.
3508 *
3509 * See the individual methods for more information and examples.
3510 */
3511
3512/**
3513 * @ngdoc method
3514 * @name $provide#provider
3515 * @description
3516 *
3517 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3518 * are constructor functions, whose instances are responsible for "providing" a factory for a
3519 * service.
3520 *
3521 * Service provider names start with the name of the service they provide followed by `Provider`.
3522 * For example, the {@link ng.$log $log} service has a provider called
3523 * {@link ng.$logProvider $logProvider}.
3524 *
3525 * Service provider objects can have additional methods which allow configuration of the provider
3526 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3527 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3528 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3529 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3530 * console or not.
3531 *
3532 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3533                        'Provider'` key.
3534 * @param {(Object|function())} provider If the provider is:
3535 *
3536 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3537 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3538 *   - `Constructor`: a new instance of the provider will be created using
3539 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3540 *
3541 * @returns {Object} registered provider instance
3542
3543 * @example
3544 *
3545 * The following example shows how to create a simple event tracking service and register it using
3546 * {@link auto.$provide#provider $provide.provider()}.
3547 *
3548 * ```js
3549 *  // Define the eventTracker provider
3550 *  function EventTrackerProvider() {
3551 *    var trackingUrl = '/track';
3552 *
3553 *    // A provider method for configuring where the tracked events should been saved
3554 *    this.setTrackingUrl = function(url) {
3555 *      trackingUrl = url;
3556 *    };
3557 *
3558 *    // The service factory function
3559 *    this.$get = ['$http', function($http) {
3560 *      var trackedEvents = {};
3561 *      return {
3562 *        // Call this to track an event
3563 *        event: function(event) {
3564 *          var count = trackedEvents[event] || 0;
3565 *          count += 1;
3566 *          trackedEvents[event] = count;
3567 *          return count;
3568 *        },
3569 *        // Call this to save the tracked events to the trackingUrl
3570 *        save: function() {
3571 *          $http.post(trackingUrl, trackedEvents);
3572 *        }
3573 *      };
3574 *    }];
3575 *  }
3576 *
3577 *  describe('eventTracker', function() {
3578 *    var postSpy;
3579 *
3580 *    beforeEach(module(function($provide) {
3581 *      // Register the eventTracker provider
3582 *      $provide.provider('eventTracker', EventTrackerProvider);
3583 *    }));
3584 *
3585 *    beforeEach(module(function(eventTrackerProvider) {
3586 *      // Configure eventTracker provider
3587 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3588 *    }));
3589 *
3590 *    it('tracks events', inject(function(eventTracker) {
3591 *      expect(eventTracker.event('login')).toEqual(1);
3592 *      expect(eventTracker.event('login')).toEqual(2);
3593 *    }));
3594 *
3595 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3596 *      postSpy = spyOn($http, 'post');
3597 *      eventTracker.event('login');
3598 *      eventTracker.save();
3599 *      expect(postSpy).toHaveBeenCalled();
3600 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3601 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3602 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3603 *    }));
3604 *  });
3605 * ```
3606 */
3607
3608/**
3609 * @ngdoc method
3610 * @name $provide#factory
3611 * @description
3612 *
3613 * Register a **service factory**, which will be called to return the service instance.
3614 * This is short for registering a service where its provider consists of only a `$get` property,
3615 * which is the given service factory function.
3616 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3617 * configure your service in a provider.
3618 *
3619 * @param {string} name The name of the instance.
3620 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3621 *                            for `$provide.provider(name, {$get: $getFn})`.
3622 * @returns {Object} registered provider instance
3623 *
3624 * @example
3625 * Here is an example of registering a service
3626 * ```js
3627 *   $provide.factory('ping', ['$http', function($http) {
3628 *     return function ping() {
3629 *       return $http.send('/ping');
3630 *     };
3631 *   }]);
3632 * ```
3633 * You would then inject and use this service like this:
3634 * ```js
3635 *   someModule.controller('Ctrl', ['ping', function(ping) {
3636 *     ping();
3637 *   }]);
3638 * ```
3639 */
3640
3641
3642/**
3643 * @ngdoc method
3644 * @name $provide#service
3645 * @description
3646 *
3647 * Register a **service constructor**, which will be invoked with `new` to create the service
3648 * instance.
3649 * This is short for registering a service where its provider's `$get` property is the service
3650 * constructor function that will be used to instantiate the service instance.
3651 *
3652 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3653 * as a type/class.
3654 *
3655 * @param {string} name The name of the instance.
3656 * @param {Function} constructor A class (constructor function) that will be instantiated.
3657 * @returns {Object} registered provider instance
3658 *
3659 * @example
3660 * Here is an example of registering a service using
3661 * {@link auto.$provide#service $provide.service(class)}.
3662 * ```js
3663 *   var Ping = function($http) {
3664 *     this.$http = $http;
3665 *   };
3666 *
3667 *   Ping.$inject = ['$http'];
3668 *
3669 *   Ping.prototype.send = function() {
3670 *     return this.$http.get('/ping');
3671 *   };
3672 *   $provide.service('ping', Ping);
3673 * ```
3674 * You would then inject and use this service like this:
3675 * ```js
3676 *   someModule.controller('Ctrl', ['ping', function(ping) {
3677 *     ping.send();
3678 *   }]);
3679 * ```
3680 */
3681
3682
3683/**
3684 * @ngdoc method
3685 * @name $provide#value
3686 * @description
3687 *
3688 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3689 * number, an array, an object or a function.  This is short for registering a service where its
3690 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3691 * service**.
3692 *
3693 * Value services are similar to constant services, except that they cannot be injected into a
3694 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3695 * an Angular
3696 * {@link auto.$provide#decorator decorator}.
3697 *
3698 * @param {string} name The name of the instance.
3699 * @param {*} value The value.
3700 * @returns {Object} registered provider instance
3701 *
3702 * @example
3703 * Here are some examples of creating value services.
3704 * ```js
3705 *   $provide.value('ADMIN_USER', 'admin');
3706 *
3707 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3708 *
3709 *   $provide.value('halfOf', function(value) {
3710 *     return value / 2;
3711 *   });
3712 * ```
3713 */
3714
3715
3716/**
3717 * @ngdoc method
3718 * @name $provide#constant
3719 * @description
3720 *
3721 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3722 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3723 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3724 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3725 *
3726 * @param {string} name The name of the constant.
3727 * @param {*} value The constant value.
3728 * @returns {Object} registered instance
3729 *
3730 * @example
3731 * Here a some examples of creating constants:
3732 * ```js
3733 *   $provide.constant('SHARD_HEIGHT', 306);
3734 *
3735 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3736 *
3737 *   $provide.constant('double', function(value) {
3738 *     return value * 2;
3739 *   });
3740 * ```
3741 */
3742
3743
3744/**
3745 * @ngdoc method
3746 * @name $provide#decorator
3747 * @description
3748 *
3749 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3750 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3751 * service. The object returned by the decorator may be the original service, or a new service
3752 * object which replaces or wraps and delegates to the original service.
3753 *
3754 * @param {string} name The name of the service to decorate.
3755 * @param {function()} decorator This function will be invoked when the service needs to be
3756 *    instantiated and should return the decorated service instance. The function is called using
3757 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3758 *    Local injection arguments:
3759 *
3760 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3761 *      decorated or delegated to.
3762 *
3763 * @example
3764 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3765 * calls to {@link ng.$log#error $log.warn()}.
3766 * ```js
3767 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3768 *     $delegate.warn = $delegate.error;
3769 *     return $delegate;
3770 *   }]);
3771 * ```
3772 */
3773
3774
3775function createInjector(modulesToLoad) {
3776  var INSTANTIATING = {},
3777      providerSuffix = 'Provider',
3778      path = [],
3779      loadedModules = new HashMap([], true),
3780      providerCache = {
3781        $provide: {
3782            provider: supportObject(provider),
3783            factory: supportObject(factory),
3784            service: supportObject(service),
3785            value: supportObject(value),
3786            constant: supportObject(constant),
3787            decorator: decorator
3788          }
3789      },
3790      providerInjector = (providerCache.$injector =
3791          createInternalInjector(providerCache, function() {
3792            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3793          })),
3794      instanceCache = {},
3795      instanceInjector = (instanceCache.$injector =
3796          createInternalInjector(instanceCache, function(servicename) {
3797            var provider = providerInjector.get(servicename + providerSuffix);
3798            return instanceInjector.invoke(provider.$get, provider);
3799          }));
3800
3801
3802  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3803
3804  return instanceInjector;
3805
3806  ////////////////////////////////////
3807  // $provider
3808  ////////////////////////////////////
3809
3810  function supportObject(delegate) {
3811    return function(key, value) {
3812      if (isObject(key)) {
3813        forEach(key, reverseParams(delegate));
3814      } else {
3815        return delegate(key, value);
3816      }
3817    };
3818  }
3819
3820  function provider(name, provider_) {
3821    assertNotHasOwnProperty(name, 'service');
3822    if (isFunction(provider_) || isArray(provider_)) {
3823      provider_ = providerInjector.instantiate(provider_);
3824    }
3825    if (!provider_.$get) {
3826      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3827    }
3828    return providerCache[name + providerSuffix] = provider_;
3829  }
3830
3831  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3832
3833  function service(name, constructor) {
3834    return factory(name, ['$injector', function($injector) {
3835      return $injector.instantiate(constructor);
3836    }]);
3837  }
3838
3839  function value(name, val) { return factory(name, valueFn(val)); }
3840
3841  function constant(name, value) {
3842    assertNotHasOwnProperty(name, 'constant');
3843    providerCache[name] = value;
3844    instanceCache[name] = value;
3845  }
3846
3847  function decorator(serviceName, decorFn) {
3848    var origProvider = providerInjector.get(serviceName + providerSuffix),
3849        orig$get = origProvider.$get;
3850
3851    origProvider.$get = function() {
3852      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3853      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3854    };
3855  }
3856
3857  ////////////////////////////////////
3858  // Module Loading
3859  ////////////////////////////////////
3860  function loadModules(modulesToLoad){
3861    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3862    forEach(modulesToLoad, function(module) {
3863      if (loadedModules.get(module)) return;
3864      loadedModules.put(module, true);
3865
3866      try {
3867        if (isString(module)) {
3868          moduleFn = angularModule(module);
3869          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3870
3871          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3872            var invokeArgs = invokeQueue[i],
3873                provider = providerInjector.get(invokeArgs[0]);
3874
3875            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3876          }
3877        } else if (isFunction(module)) {
3878            runBlocks.push(providerInjector.invoke(module));
3879        } else if (isArray(module)) {
3880            runBlocks.push(providerInjector.invoke(module));
3881        } else {
3882          assertArgFn(module, 'module');
3883        }
3884      } catch (e) {
3885        if (isArray(module)) {
3886          module = module[module.length - 1];
3887        }
3888        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3889          // Safari & FF's stack traces don't contain error.message content
3890          // unlike those of Chrome and IE
3891          // So if stack doesn't contain message, we create a new string that contains both.
3892          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3893          /* jshint -W022 */
3894          e = e.message + '\n' + e.stack;
3895        }
3896        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3897                  module, e.stack || e.message || e);
3898      }
3899    });
3900    return runBlocks;
3901  }
3902
3903  ////////////////////////////////////
3904  // internal Injector
3905  ////////////////////////////////////
3906
3907  function createInternalInjector(cache, factory) {
3908
3909    function getService(serviceName) {
3910      if (cache.hasOwnProperty(serviceName)) {
3911        if (cache[serviceName] === INSTANTIATING) {
3912          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
3913                    serviceName + ' <- ' + path.join(' <- '));
3914        }
3915        return cache[serviceName];
3916      } else {
3917        try {
3918          path.unshift(serviceName);
3919          cache[serviceName] = INSTANTIATING;
3920          return cache[serviceName] = factory(serviceName);
3921        } catch (err) {
3922          if (cache[serviceName] === INSTANTIATING) {
3923            delete cache[serviceName];
3924          }
3925          throw err;
3926        } finally {
3927          path.shift();
3928        }
3929      }
3930    }
3931
3932    function invoke(fn, self, locals){
3933      var args = [],
3934          $inject = annotate(fn),
3935          length, i,
3936          key;
3937
3938      for(i = 0, length = $inject.length; i < length; i++) {
3939        key = $inject[i];
3940        if (typeof key !== 'string') {
3941          throw $injectorMinErr('itkn',
3942                  'Incorrect injection token! Expected service name as string, got {0}', key);
3943        }
3944        args.push(
3945          locals && locals.hasOwnProperty(key)
3946          ? locals[key]
3947          : getService(key)
3948        );
3949      }
3950      if (isArray(fn)) {
3951        fn = fn[length];
3952      }
3953
3954      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3955      // #5388
3956      return fn.apply(self, args);
3957    }
3958
3959    function instantiate(Type, locals) {
3960      var Constructor = function() {},
3961          instance, returnedValue;
3962
3963      // Check if Type is annotated and use just the given function at n-1 as parameter
3964      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3965      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3966      instance = new Constructor();
3967      returnedValue = invoke(Type, instance, locals);
3968
3969      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3970    }
3971
3972    return {
3973      invoke: invoke,
3974      instantiate: instantiate,
3975      get: getService,
3976      annotate: annotate,
3977      has: function(name) {
3978        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3979      }
3980    };
3981  }
3982}
3983
3984/**
3985 * @ngdoc service
3986 * @name $anchorScroll
3987 * @kind function
3988 * @requires $window
3989 * @requires $location
3990 * @requires $rootScope
3991 *
3992 * @description
3993 * When called, it checks current value of `$location.hash()` and scrolls to the related element,
3994 * according to rules specified in
3995 * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
3996 *
3997 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3998 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3999 *
4000 * @example
4001   <example>
4002     <file name="index.html">
4003       <div id="scrollArea" ng-controller="ScrollCtrl">
4004         <a ng-click="gotoBottom()">Go to bottom</a>
4005         <a id="bottom"></a> You're at the bottom!
4006       </div>
4007     </file>
4008     <file name="script.js">
4009       function ScrollCtrl($scope, $location, $anchorScroll) {
4010         $scope.gotoBottom = function (){
4011           // set the location.hash to the id of
4012           // the element you wish to scroll to.
4013           $location.hash('bottom');
4014
4015           // call $anchorScroll()
4016           $anchorScroll();
4017         };
4018       }
4019     </file>
4020     <file name="style.css">
4021       #scrollArea {
4022         height: 350px;
4023         overflow: auto;
4024       }
4025
4026       #bottom {
4027         display: block;
4028         margin-top: 2000px;
4029       }
4030     </file>
4031   </example>
4032 */
4033function $AnchorScrollProvider() {
4034
4035  var autoScrollingEnabled = true;
4036
4037  this.disableAutoScrolling = function() {
4038    autoScrollingEnabled = false;
4039  };
4040
4041  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4042    var document = $window.document;
4043
4044    // helper function to get first anchor from a NodeList
4045    // can't use filter.filter, as it accepts only instances of Array
4046    // and IE can't convert NodeList to an array using [].slice
4047    // TODO(vojta): use filter if we change it to accept lists as well
4048    function getFirstAnchor(list) {
4049      var result = null;
4050      forEach(list, function(element) {
4051        if (!result && lowercase(element.nodeName) === 'a') result = element;
4052      });
4053      return result;
4054    }
4055
4056    function scroll() {
4057      var hash = $location.hash(), elm;
4058
4059      // empty hash, scroll to the top of the page
4060      if (!hash) $window.scrollTo(0, 0);
4061
4062      // element with given id
4063      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4064
4065      // first anchor with given name :-D
4066      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4067
4068      // no element and hash == 'top', scroll to the top of the page
4069      else if (hash === 'top') $window.scrollTo(0, 0);
4070    }
4071
4072    // does not scroll when user clicks on anchor link that is currently on
4073    // (no url change, no $location.hash() change), browser native does scroll
4074    if (autoScrollingEnabled) {
4075      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4076        function autoScrollWatchAction() {
4077          $rootScope.$evalAsync(scroll);
4078        });
4079    }
4080
4081    return scroll;
4082  }];
4083}
4084
4085var $animateMinErr = minErr('$animate');
4086
4087/**
4088 * @ngdoc provider
4089 * @name $animateProvider
4090 *
4091 * @description
4092 * Default implementation of $animate that doesn't perform any animations, instead just
4093 * synchronously performs DOM
4094 * updates and calls done() callbacks.
4095 *
4096 * In order to enable animations the ngAnimate module has to be loaded.
4097 *
4098 * To see the functional implementation check out src/ngAnimate/animate.js
4099 */
4100var $AnimateProvider = ['$provide', function($provide) {
4101
4102
4103  this.$$selectors = {};
4104
4105
4106  /**
4107   * @ngdoc method
4108   * @name $animateProvider#register
4109   *
4110   * @description
4111   * Registers a new injectable animation factory function. The factory function produces the
4112   * animation object which contains callback functions for each event that is expected to be
4113   * animated.
4114   *
4115   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4116   *   must be called once the element animation is complete. If a function is returned then the
4117   *   animation service will use this function to cancel the animation whenever a cancel event is
4118   *   triggered.
4119   *
4120   *
4121   * ```js
4122   *   return {
4123     *     eventFn : function(element, done) {
4124     *       //code to run the animation
4125     *       //once complete, then run done()
4126     *       return function cancellationFunction() {
4127     *         //code to cancel the animation
4128     *       }
4129     *     }
4130     *   }
4131   * ```
4132   *
4133   * @param {string} name The name of the animation.
4134   * @param {Function} factory The factory function that will be executed to return the animation
4135   *                           object.
4136   */
4137  this.register = function(name, factory) {
4138    var key = name + '-animation';
4139    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4140        "Expecting class selector starting with '.' got '{0}'.", name);
4141    this.$$selectors[name.substr(1)] = key;
4142    $provide.factory(key, factory);
4143  };
4144
4145  /**
4146   * @ngdoc method
4147   * @name $animateProvider#classNameFilter
4148   *
4149   * @description
4150   * Sets and/or returns the CSS class regular expression that is checked when performing
4151   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4152   * therefore enable $animate to attempt to perform an animation on any element.
4153   * When setting the classNameFilter value, animations will only be performed on elements
4154   * that successfully match the filter expression. This in turn can boost performance
4155   * for low-powered devices as well as applications containing a lot of structural operations.
4156   * @param {RegExp=} expression The className expression which will be checked against all animations
4157   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4158   */
4159  this.classNameFilter = function(expression) {
4160    if(arguments.length === 1) {
4161      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4162    }
4163    return this.$$classNameFilter;
4164  };
4165
4166  this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
4167
4168    function async(fn) {
4169      fn && $$asyncCallback(fn);
4170    }
4171
4172    /**
4173     *
4174     * @ngdoc service
4175     * @name $animate
4176     * @description The $animate service provides rudimentary DOM manipulation functions to
4177     * insert, remove and move elements within the DOM, as well as adding and removing classes.
4178     * This service is the core service used by the ngAnimate $animator service which provides
4179     * high-level animation hooks for CSS and JavaScript.
4180     *
4181     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4182     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4183     * manipulation operations.
4184     *
4185     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4186     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4187     * page}.
4188     */
4189    return {
4190
4191      /**
4192       *
4193       * @ngdoc method
4194       * @name $animate#enter
4195       * @kind function
4196       * @description Inserts the element into the DOM either after the `after` element or within
4197       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4198       * @param {DOMElement} element the element which will be inserted into the DOM
4199       * @param {DOMElement} parent the parent element which will append the element as
4200       *   a child (if the after element is not present)
4201       * @param {DOMElement} after the sibling element which will append the element
4202       *   after itself
4203       * @param {Function=} done callback function that will be called after the element has been
4204       *   inserted into the DOM
4205       */
4206      enter : function(element, parent, after, done) {
4207        if (after) {
4208          after.after(element);
4209        } else {
4210          if (!parent || !parent[0]) {
4211            parent = after.parent();
4212          }
4213          parent.append(element);
4214        }
4215        async(done);
4216      },
4217
4218      /**
4219       *
4220       * @ngdoc method
4221       * @name $animate#leave
4222       * @kind function
4223       * @description Removes the element from the DOM. Once complete, the done() callback will be
4224       *   fired (if provided).
4225       * @param {DOMElement} element the element which will be removed from the DOM
4226       * @param {Function=} done callback function that will be called after the element has been
4227       *   removed from the DOM
4228       */
4229      leave : function(element, done) {
4230        element.remove();
4231        async(done);
4232      },
4233
4234      /**
4235       *
4236       * @ngdoc method
4237       * @name $animate#move
4238       * @kind function
4239       * @description Moves the position of the provided element within the DOM to be placed
4240       * either after the `after` element or inside of the `parent` element. Once complete, the
4241       * done() callback will be fired (if provided).
4242       *
4243       * @param {DOMElement} element the element which will be moved around within the
4244       *   DOM
4245       * @param {DOMElement} parent the parent element where the element will be
4246       *   inserted into (if the after element is not present)
4247       * @param {DOMElement} after the sibling element where the element will be
4248       *   positioned next to
4249       * @param {Function=} done the callback function (if provided) that will be fired after the
4250       *   element has been moved to its new position
4251       */
4252      move : function(element, parent, after, done) {
4253        // Do not remove element before insert. Removing will cause data associated with the
4254        // element to be dropped. Insert will implicitly do the remove.
4255        this.enter(element, parent, after, done);
4256      },
4257
4258      /**
4259       *
4260       * @ngdoc method
4261       * @name $animate#addClass
4262       * @kind function
4263       * @description Adds the provided className CSS class value to the provided element. Once
4264       * complete, the done() callback will be fired (if provided).
4265       * @param {DOMElement} element the element which will have the className value
4266       *   added to it
4267       * @param {string} className the CSS class which will be added to the element
4268       * @param {Function=} done the callback function (if provided) that will be fired after the
4269       *   className value has been added to the element
4270       */
4271      addClass : function(element, className, done) {
4272        className = isString(className) ?
4273                      className :
4274                      isArray(className) ? className.join(' ') : '';
4275        forEach(element, function (element) {
4276          jqLiteAddClass(element, className);
4277        });
4278        async(done);
4279      },
4280
4281      /**
4282       *
4283       * @ngdoc method
4284       * @name $animate#removeClass
4285       * @kind function
4286       * @description Removes the provided className CSS class value from the provided element.
4287       * Once complete, the done() callback will be fired (if provided).
4288       * @param {DOMElement} element the element which will have the className value
4289       *   removed from it
4290       * @param {string} className the CSS class which will be removed from the element
4291       * @param {Function=} done the callback function (if provided) that will be fired after the
4292       *   className value has been removed from the element
4293       */
4294      removeClass : function(element, className, done) {
4295        className = isString(className) ?
4296                      className :
4297                      isArray(className) ? className.join(' ') : '';
4298        forEach(element, function (element) {
4299          jqLiteRemoveClass(element, className);
4300        });
4301        async(done);
4302      },
4303
4304      /**
4305       *
4306       * @ngdoc method
4307       * @name $animate#setClass
4308       * @kind function
4309       * @description Adds and/or removes the given CSS classes to and from the element.
4310       * Once complete, the done() callback will be fired (if provided).
4311       * @param {DOMElement} element the element which will have its CSS classes changed
4312       *   removed from it
4313       * @param {string} add the CSS classes which will be added to the element
4314       * @param {string} remove the CSS class which will be removed from the element
4315       * @param {Function=} done the callback function (if provided) that will be fired after the
4316       *   CSS classes have been set on the element
4317       */
4318      setClass : function(element, add, remove, done) {
4319        forEach(element, function (element) {
4320          jqLiteAddClass(element, add);
4321          jqLiteRemoveClass(element, remove);
4322        });
4323        async(done);
4324      },
4325
4326      enabled : noop
4327    };
4328  }];
4329}];
4330
4331function $$AsyncCallbackProvider(){
4332  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4333    return $$rAF.supported
4334      ? function(fn) { return $$rAF(fn); }
4335      : function(fn) {
4336        return $timeout(fn, 0, false);
4337      };
4338  }];
4339}
4340
4341/**
4342 * ! This is a private undocumented service !
4343 *
4344 * @name $browser
4345 * @requires $log
4346 * @description
4347 * This object has two goals:
4348 *
4349 * - hide all the global state in the browser caused by the window object
4350 * - abstract away all the browser specific features and inconsistencies
4351 *
4352 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4353 * service, which can be used for convenient testing of the application without the interaction with
4354 * the real browser apis.
4355 */
4356/**
4357 * @param {object} window The global window object.
4358 * @param {object} document jQuery wrapped document.
4359 * @param {function()} XHR XMLHttpRequest constructor.
4360 * @param {object} $log console.log or an object with the same interface.
4361 * @param {object} $sniffer $sniffer service
4362 */
4363function Browser(window, document, $log, $sniffer) {
4364  var self = this,
4365      rawDocument = document[0],
4366      location = window.location,
4367      history = window.history,
4368      setTimeout = window.setTimeout,
4369      clearTimeout = window.clearTimeout,
4370      pendingDeferIds = {};
4371
4372  self.isMock = false;
4373
4374  var outstandingRequestCount = 0;
4375  var outstandingRequestCallbacks = [];
4376
4377  // TODO(vojta): remove this temporary api
4378  self.$$completeOutstandingRequest = completeOutstandingRequest;
4379  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4380
4381  /**
4382   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4383   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4384   */
4385  function completeOutstandingRequest(fn) {
4386    try {
4387      fn.apply(null, sliceArgs(arguments, 1));
4388    } finally {
4389      outstandingRequestCount--;
4390      if (outstandingRequestCount === 0) {
4391        while(outstandingRequestCallbacks.length) {
4392          try {
4393            outstandingRequestCallbacks.pop()();
4394          } catch (e) {
4395            $log.error(e);
4396          }
4397        }
4398      }
4399    }
4400  }
4401
4402  /**
4403   * @private
4404   * Note: this method is used only by scenario runner
4405   * TODO(vojta): prefix this method with $$ ?
4406   * @param {function()} callback Function that will be called when no outstanding request
4407   */
4408  self.notifyWhenNoOutstandingRequests = function(callback) {
4409    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4410    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4411    // regular poller would result in flaky tests.
4412    forEach(pollFns, function(pollFn){ pollFn(); });
4413
4414    if (outstandingRequestCount === 0) {
4415      callback();
4416    } else {
4417      outstandingRequestCallbacks.push(callback);
4418    }
4419  };
4420
4421  //////////////////////////////////////////////////////////////
4422  // Poll Watcher API
4423  //////////////////////////////////////////////////////////////
4424  var pollFns = [],
4425      pollTimeout;
4426
4427  /**
4428   * @name $browser#addPollFn
4429   *
4430   * @param {function()} fn Poll function to add
4431   *
4432   * @description
4433   * Adds a function to the list of functions that poller periodically executes,
4434   * and starts polling if not started yet.
4435   *
4436   * @returns {function()} the added function
4437   */
4438  self.addPollFn = function(fn) {
4439    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4440    pollFns.push(fn);
4441    return fn;
4442  };
4443
4444  /**
4445   * @param {number} interval How often should browser call poll functions (ms)
4446   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4447   *
4448   * @description
4449   * Configures the poller to run in the specified intervals, using the specified
4450   * setTimeout fn and kicks it off.
4451   */
4452  function startPoller(interval, setTimeout) {
4453    (function check() {
4454      forEach(pollFns, function(pollFn){ pollFn(); });
4455      pollTimeout = setTimeout(check, interval);
4456    })();
4457  }
4458
4459  //////////////////////////////////////////////////////////////
4460  // URL API
4461  //////////////////////////////////////////////////////////////
4462
4463  var lastBrowserUrl = location.href,
4464      baseElement = document.find('base'),
4465      newLocation = null;
4466
4467  /**
4468   * @name $browser#url
4469   *
4470   * @description
4471   * GETTER:
4472   * Without any argument, this method just returns current value of location.href.
4473   *
4474   * SETTER:
4475   * With at least one argument, this method sets url to new value.
4476   * If html5 history api supported, pushState/replaceState is used, otherwise
4477   * location.href/location.replace is used.
4478   * Returns its own instance to allow chaining
4479   *
4480   * NOTE: this api is intended for use only by the $location service. Please use the
4481   * {@link ng.$location $location service} to change url.
4482   *
4483   * @param {string} url New url (when used as setter)
4484   * @param {boolean=} replace Should new url replace current history record ?
4485   */
4486  self.url = function(url, replace) {
4487    // Android Browser BFCache causes location, history reference to become stale.
4488    if (location !== window.location) location = window.location;
4489    if (history !== window.history) history = window.history;
4490
4491    // setter
4492    if (url) {
4493      if (lastBrowserUrl == url) return;
4494      lastBrowserUrl = url;
4495      if ($sniffer.history) {
4496        if (replace) history.replaceState(null, '', url);
4497        else {
4498          history.pushState(null, '', url);
4499          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4500          baseElement.attr('href', baseElement.attr('href'));
4501        }
4502      } else {
4503        newLocation = url;
4504        if (replace) {
4505          location.replace(url);
4506        } else {
4507          location.href = url;
4508        }
4509      }
4510      return self;
4511    // getter
4512    } else {
4513      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4514      //   methods not updating location.href synchronously.
4515      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4516      return newLocation || location.href.replace(/%27/g,"'");
4517    }
4518  };
4519
4520  var urlChangeListeners = [],
4521      urlChangeInit = false;
4522
4523  function fireUrlChange() {
4524    newLocation = null;
4525    if (lastBrowserUrl == self.url()) return;
4526
4527    lastBrowserUrl = self.url();
4528    forEach(urlChangeListeners, function(listener) {
4529      listener(self.url());
4530    });
4531  }
4532
4533  /**
4534   * @name $browser#onUrlChange
4535   *
4536   * @description
4537   * Register callback function that will be called, when url changes.
4538   *
4539   * It's only called when the url is changed from outside of angular:
4540   * - user types different url into address bar
4541   * - user clicks on history (forward/back) button
4542   * - user clicks on a link
4543   *
4544   * It's not called when url is changed by $browser.url() method
4545   *
4546   * The listener gets called with new url as parameter.
4547   *
4548   * NOTE: this api is intended for use only by the $location service. Please use the
4549   * {@link ng.$location $location service} to monitor url changes in angular apps.
4550   *
4551   * @param {function(string)} listener Listener function to be called when url changes.
4552   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4553   */
4554  self.onUrlChange = function(callback) {
4555    // TODO(vojta): refactor to use node's syntax for events
4556    if (!urlChangeInit) {
4557      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4558      // don't fire popstate when user change the address bar and don't fire hashchange when url
4559      // changed by push/replaceState
4560
4561      // html5 history api - popstate event
4562      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4563      // hashchange event
4564      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4565      // polling
4566      else self.addPollFn(fireUrlChange);
4567
4568      urlChangeInit = true;
4569    }
4570
4571    urlChangeListeners.push(callback);
4572    return callback;
4573  };
4574
4575  //////////////////////////////////////////////////////////////
4576  // Misc API
4577  //////////////////////////////////////////////////////////////
4578
4579  /**
4580   * @name $browser#baseHref
4581   *
4582   * @description
4583   * Returns current <base href>
4584   * (always relative - without domain)
4585   *
4586   * @returns {string} The current base href
4587   */
4588  self.baseHref = function() {
4589    var href = baseElement.attr('href');
4590    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4591  };
4592
4593  //////////////////////////////////////////////////////////////
4594  // Cookies API
4595  //////////////////////////////////////////////////////////////
4596  var lastCookies = {};
4597  var lastCookieString = '';
4598  var cookiePath = self.baseHref();
4599
4600  /**
4601   * @name $browser#cookies
4602   *
4603   * @param {string=} name Cookie name
4604   * @param {string=} value Cookie value
4605   *
4606   * @description
4607   * The cookies method provides a 'private' low level access to browser cookies.
4608   * It is not meant to be used directly, use the $cookie service instead.
4609   *
4610   * The return values vary depending on the arguments that the method was called with as follows:
4611   *
4612   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4613   *   it
4614   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4615   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4616   *   way)
4617   *
4618   * @returns {Object} Hash of all cookies (if called without any parameter)
4619   */
4620  self.cookies = function(name, value) {
4621    /* global escape: false, unescape: false */
4622    var cookieLength, cookieArray, cookie, i, index;
4623
4624    if (name) {
4625      if (value === undefined) {
4626        rawDocument.cookie = escape(name) + "=;
4626path=" + cookiePath +
4627                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4628      } else {
4629        if (isString(value)) {
4630          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4631                                ';path=' + cookiePath).length + 1;
4632
4633          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4634          // - 300 cookies
4635          // - 20 cookies per unique domain
4636          // - 4096 bytes per cookie
4637          if (cookieLength > 4096) {
4638            $log.warn("Cookie '"+ name +
4639              "' possibly not set or overflowed because it was too large ("+
4640              cookieLength + " > 4096 bytes)!");
4641          }
4642        }
4643      }
4644    } else {
4645      if (rawDocument.cookie !== lastCookieString) {
4646        lastCookieString = rawDocument.cookie;
4647        cookieArray = lastCookieString.split("; ");
4648        lastCookies = {};
4649
4650        for (i = 0; i < cookieArray.length; i++) {
4651          cookie = cookieArray[i];
4652          index = cookie.indexOf('=');
4653          if (index > 0) { //ignore nameless cookies
4654            name = unescape(cookie.substring(0, index));
4655            // the first value that is seen for a cookie is the most
4656            // specific one.  values for the same cookie name that
4657            // follow are for less specific paths.
4658            if (lastCookies[name] === undefined) {
4659              lastCookies[name] = unescape(cookie.substring(index + 1));
4660            }
4661          }
4662        }
4663      }
4664      return lastCookies;
4665    }
4666  };
4667
4668
4669  /**
4670   * @name $browser#defer
4671   * @param {function()} fn A function, who's execution should be deferred.
4672   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4673   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4674   *
4675   * @description
4676   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4677   *
4678   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4679   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4680   * via `$browser.defer.flush()`.
4681   *
4682   */
4683  self.defer = function(fn, delay) {
4684    var timeoutId;
4685    outstandingRequestCount++;
4686    timeoutId = setTimeout(function() {
4687      delete pendingDeferIds[timeoutId];
4688      completeOutstandingRequest(fn);
4689    }, delay || 0);
4690    pendingDeferIds[timeoutId] = true;
4691    return timeoutId;
4692  };
4693
4694
4695  /**
4696   * @name $browser#defer.cancel
4697   *
4698   * @description
4699   * Cancels a deferred task identified with `deferId`.
4700   *
4701   * @param {*} deferId Token returned by the `$browser.defer` function.
4702   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4703   *                    canceled.
4704   */
4705  self.defer.cancel = function(deferId) {
4706    if (pendingDeferIds[deferId]) {
4707      delete pendingDeferIds[deferId];
4708      clearTimeout(deferId);
4709      completeOutstandingRequest(noop);
4710      return true;
4711    }
4712    return false;
4713  };
4714
4715}
4716
4717function $BrowserProvider(){
4718  this.$get = ['$window', '$log', '$sniffer', '$document',
4719      function( $window,   $log,   $sniffer,   $document){
4720        return new Browser($window, $document, $log, $sniffer);
4721      }];
4722}
4723
4724/**
4725 * @ngdoc service
4726 * @name $cacheFactory
4727 *
4728 * @description
4729 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4730 * them.
4731 *
4732 * ```js
4733 *
4734 *  var cache = $cacheFactory('cacheId');
4735 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4736 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4737 *
4738 *  cache.put("key", "value");
4739 *  cache.put("another key", "another value");
4740 *
4741 *  // We've specified no options on creation
4742 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4743 *
4744 * ```
4745 *
4746 *
4747 * @param {string} cacheId Name or id of the newly created cache.
4748 * @param {object=} options Options object that specifies the cache behavior. Properties:
4749 *
4750 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4751 *
4752 * @returns {object} Newly created cache object with the following set of methods:
4753 *
4754 * - `{object}` `info()` — Returns id, size, and options of cache.
4755 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4756 *   it.
4757 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4758 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4759 * - `{void}` `removeAll()` — Removes all cached values.
4760 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4761 *
4762 * @example
4763   <example module="cacheExampleApp">
4764     <file name="index.html">
4765       <div ng-controller="CacheController">
4766         <input ng-model="newCacheKey" placeholder="Key">
4767         <input ng-model="newCacheValue" placeholder="Value">
4768         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4769
4770         <p ng-if="keys.length">Cached Values</p>
4771         <div ng-repeat="key in keys">
4772           <span ng-bind="key"></span>
4773           <span>: </span>
4774           <b ng-bind="cache.get(key)"></b>
4775         </div>
4776
4777         <p>Cache Info</p>
4778         <div ng-repeat="(key, value) in cache.info()">
4779           <span ng-bind="key"></span>
4780           <span>: </span>
4781           <b ng-bind="value"></b>
4782         </div>
4783       </div>
4784     </file>
4785     <file name="script.js">
4786       angular.module('cacheExampleApp', []).
4787         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4788           $scope.keys = [];
4789           $scope.cache = $cacheFactory('cacheId');
4790           $scope.put = function(key, value) {
4791             $scope.cache.put(key, value);
4792             $scope.keys.push(key);
4793           };
4794         }]);
4795     </file>
4796     <file name="style.css">
4797       p {
4798         margin: 10px 0 3px;
4799       }
4800     </file>
4801   </example>
4802 */
4803function $CacheFactoryProvider() {
4804
4805  this.$get = function() {
4806    var caches = {};
4807
4808    function cacheFactory(cacheId, options) {
4809      if (cacheId in caches) {
4810        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4811      }
4812
4813      var size = 0,
4814          stats = extend({}, options, {id: cacheId}),
4815          data = {},
4816          capacity = (options && options.capacity) || Number.MAX_VALUE,
4817          lruHash = {},
4818          freshEnd = null,
4819          staleEnd = null;
4820
4821      /**
4822       * @ngdoc type
4823       * @name $cacheFactory.Cache
4824       *
4825       * @description
4826       * A cache object used to store and retrieve data, primarily used by
4827       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4828       * templates and other data.
4829       *
4830       * ```js
4831       *  angular.module('superCache')
4832       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4833       *      return $cacheFactory('super-cache');
4834       *    }]);
4835       * ```
4836       *
4837       * Example test:
4838       *
4839       * ```js
4840       *  it('should behave like a cache', inject(function(superCache) {
4841       *    superCache.put('key', 'value');
4842       *    superCache.put('another key', 'another value');
4843       *
4844       *    expect(superCache.info()).toEqual({
4845       *      id: 'super-cache',
4846       *      size: 2
4847       *    });
4848       *
4849       *    superCache.remove('another key');
4850       *    expect(superCache.get('another key')).toBeUndefined();
4851       *
4852       *    superCache.removeAll();
4853       *    expect(superCache.info()).toEqual({
4854       *      id: 'super-cache',
4855       *      size: 0
4856       *    });
4857       *  }));
4858       * ```
4859       */
4860      return caches[cacheId] = {
4861
4862        /**
4863         * @ngdoc method
4864         * @name $cacheFactory.Cache#put
4865         * @kind function
4866         *
4867         * @description
4868         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4869         * retrieved later, and incrementing the size of the cache if the key was not already
4870         * present in the cache. If behaving like an LRU cache, it will also remove stale
4871         * entries from the set.
4872         *
4873         * It will not insert undefined values into the cache.
4874         *
4875         * @param {string} key the key under which the cached data is stored.
4876         * @param {*} value the value to store alongside the key. If it is undefined, the key
4877         *    will not be stored.
4878         * @returns {*} the value stored.
4879         */
4880        put: function(key, value) {
4881          if (capacity < Number.MAX_VALUE) {
4882            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4883
4884            refresh(lruEntry);
4885          }
4886
4887          if (isUndefined(value)) return;
4888          if (!(key in data)) size++;
4889          data[key] = value;
4890
4891          if (size > capacity) {
4892            this.remove(staleEnd.key);
4893          }
4894
4895          return value;
4896        },
4897
4898        /**
4899         * @ngdoc method
4900         * @name $cacheFactory.Cache#get
4901         * @kind function
4902         *
4903         * @description
4904         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4905         *
4906         * @param {string} key the key of the data to be retrieved
4907         * @returns {*} the value stored.
4908         */
4909        get: function(key) {
4910          if (capacity < Number.MAX_VALUE) {
4911            var lruEntry = lruHash[key];
4912
4913            if (!lruEntry) return;
4914
4915            refresh(lruEntry);
4916          }
4917
4918          return data[key];
4919        },
4920
4921
4922        /**
4923         * @ngdoc method
4924         * @name $cacheFactory.Cache#remove
4925         * @kind function
4926         *
4927         * @description
4928         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4929         *
4930         * @param {string} key the key of the entry to be removed
4931         */
4932        remove: function(key) {
4933          if (capacity < Number.MAX_VALUE) {
4934            var lruEntry = lruHash[key];
4935
4936            if (!lruEntry) return;
4937
4938            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4939            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4940            link(lruEntry.n,lruEntry.p);
4941
4942            delete lruHash[key];
4943          }
4944
4945          delete data[key];
4946          size--;
4947        },
4948
4949
4950        /**
4951         * @ngdoc method
4952         * @name $cacheFactory.Cache#removeAll
4953         * @kind function
4954         *
4955         * @description
4956         * Clears the cache object of any entries.
4957         */
4958        removeAll: function() {
4959          data = {};
4960          size = 0;
4961          lruHash = {};
4962          freshEnd = staleEnd = null;
4963        },
4964
4965
4966        /**
4967         * @ngdoc method
4968         * @name $cacheFactory.Cache#destroy
4969         * @kind function
4970         *
4971         * @description
4972         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
4973         * removing it from the {@link $cacheFactory $cacheFactory} set.
4974         */
4975        destroy: function() {
4976          data = null;
4977          stats = null;
4978          lruHash = null;
4979          delete caches[cacheId];
4980        },
4981
4982
4983        /**
4984         * @ngdoc method
4985         * @name $cacheFactory.Cache#info
4986         * @kind function
4987         *
4988         * @description
4989         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
4990         *
4991         * @returns {object} an object with the following properties:
4992         *   <ul>
4993         *     <li>**id**: the id of the cache instance</li>
4994         *     <li>**size**: the number of entries kept in the cache instance</li>
4995         *     <li>**...**: any additional properties from the options object when creating the
4996         *       cache.</li>
4997         *   </ul>
4998         */
4999        info: function() {
5000          return extend({}, stats, {size: size});
5001        }
5002      };
5003
5004
5005      /**
5006       * makes the `entry` the freshEnd of the LRU linked list
5007       */
5008      function refresh(entry) {
5009        if (entry != freshEnd) {
5010          if (!staleEnd) {
5011            staleEnd = entry;
5012          } else if (staleEnd == entry) {
5013            staleEnd = entry.n;
5014          }
5015
5016          link(entry.n, entry.p);
5017          link(entry, freshEnd);
5018          freshEnd = entry;
5019          freshEnd.n = null;
5020        }
5021      }
5022
5023
5024      /**
5025       * bidirectionally links two entries of the LRU linked list
5026       */
5027      function link(nextEntry, prevEntry) {
5028        if (nextEntry != prevEntry) {
5029          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5030          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5031        }
5032      }
5033    }
5034
5035
5036  /**
5037   * @ngdoc method
5038   * @name $cacheFactory#info
5039   *
5040   * @description
5041   * Get information about all the caches that have been created
5042   *
5043   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5044   */
5045    cacheFactory.info = function() {
5046      var info = {};
5047      forEach(caches, function(cache, cacheId) {
5048        info[cacheId] = cache.info();
5049      });
5050      return info;
5051    };
5052
5053
5054  /**
5055   * @ngdoc method
5056   * @name $cacheFactory#get
5057   *
5058   * @description
5059   * Get access to a cache object by the `cacheId` used when it was created.
5060   *
5061   * @param {string} cacheId Name or id of a cache to access.
5062   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5063   */
5064    cacheFactory.get = function(cacheId) {
5065      return caches[cacheId];
5066    };
5067
5068
5069    return cacheFactory;
5070  };
5071}
5072
5073/**
5074 * @ngdoc service
5075 * @name $templateCache
5076 *
5077 * @description
5078 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5079 * can load templates directly into the cache in a `script` tag, or by consuming the
5080 * `$templateCache` service directly.
5081 *
5082 * Adding via the `script` tag:
5083 *
5084 * ```html
5085 *   <script type="text/ng-template" id="templateId.html">
5086 *     <p>This is the content of the template</p>
5087 *   </script>
5088 * ```
5089 *
5090 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5091 * the document, but it must be below the `ng-app` definition.
5092 *
5093 * Adding via the $templateCache service:
5094 *
5095 * ```js
5096 * var myApp = angular.module('myApp', []);
5097 * myApp.run(function($templateCache) {
5098 *   $templateCache.put('templateId.html', 'This is the content of the template');
5099 * });
5100 * ```
5101 *
5102 * To retrieve the template later, simply use it in your HTML:
5103 * ```html
5104 * <div ng-include=" 'templateId.html' "></div>
5105 * ```
5106 *
5107 * or get it via Javascript:
5108 * ```js
5109 * $templateCache.get('templateId.html')
5110 * ```
5111 *
5112 * See {@link ng.$cacheFactory $cacheFactory}.
5113 *
5114 */
5115function $TemplateCacheProvider() {
5116  this.$get = ['$cacheFactory', function($cacheFactory) {
5117    return $cacheFactory('templates');
5118  }];
5119}
5120
5121/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5122 *
5123 * DOM-related variables:
5124 *
5125 * - "node" - DOM Node
5126 * - "element" - DOM Element or Node
5127 * - "$node" or "$element" - jqLite-wrapped node or element
5128 *
5129 *
5130 * Compiler related stuff:
5131 *
5132 * - "linkFn" - linking fn of a single directive
5133 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5134 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5135 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5136 */
5137
5138
5139/**
5140 * @ngdoc service
5141 * @name $compile
5142 * @kind function
5143 *
5144 * @description
5145 * Compiles an HTML string or DOM into a template and produces a template function, which
5146 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5147 *
5148 * The compilation is a process of walking the DOM tree and matching DOM elements to
5149 * {@link ng.$compileProvider#directive directives}.
5150 *
5151 * <div class="alert alert-warning">
5152 * **Note:** This document is an in-depth reference of all directive options.
5153 * For a gentle introduction to directives with examples of common use cases,
5154 * see the {@link guide/directive directive guide}.
5155 * </div>
5156 *
5157 * ## Comprehensive Directive API
5158 *
5159 * There are many different options for a directive.
5160 *
5161 * The difference resides in the return value of the factory function.
5162 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5163 * or just the `postLink` function (all other properties will have the default values).
5164 *
5165 * <div class="alert alert-success">
5166 * **Best Practice:** It's recommended to use the "directive definition object" form.
5167 * </div>
5168 *
5169 * Here's an example directive declared with a Directive Definition Object:
5170 *
5171 * ```js
5172 *   var myModule = angular.module(...);
5173 *
5174 *   myModule.directive('directiveName', function factory(injectables) {
5175 *     var directiveDefinitionObject = {
5176 *       priority: 0,
5177 *       template: '<div></div>
5177', // or // function(tElement, tAttrs) { ... },
5178 *       // or
5179 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5180 *       transclude: false,
5181 *       restrict: 'A',
5182 *       scope: false,
5183 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5184 *       controllerAs: 'stringAlias',
5185 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5186 *       compile: function compile(tElement, tAttrs, transclude) {
5187 *         return {
5188 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5189 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5190 *         }
5191 *         // or
5192 *         // return function postLink( ... ) { ... }
5193 *       },
5194 *       // or
5195 *       // link: {
5196 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5197 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5198 *       // }
5199 *       // or
5200 *       // link: function postLink( ... ) { ... }
5201 *     };
5202 *     return directiveDefinitionObject;
5203 *   });
5204 * ```
5205 *
5206 * <div class="alert alert-warning">
5207 * **Note:** Any unspecified options will use the default value. You can see the default values below.
5208 * </div>
5209 *
5210 * Therefore the above can be simplified as:
5211 *
5212 * ```js
5213 *   var myModule = angular.module(...);
5214 *
5215 *   myModule.directive('directiveName', function factory(injectables) {
5216 *     var directiveDefinitionObject = {
5217 *       link: function postLink(scope, iElement, iAttrs) { ... }
5218 *     };
5219 *     return directiveDefinitionObject;
5220 *     // or
5221 *     // return function postLink(scope, iElement, iAttrs) { ... }
5222 *   });
5223 * ```
5224 *
5225 *
5226 *
5227 * ### Directive Definition Object
5228 *
5229 * The directive definition object provides instructions to the {@link ng.$compile
5230 * compiler}. The attributes are:
5231 *
5232 * #### `priority`
5233 * When there are multiple directives defined on a single DOM element, sometimes it
5234 * is necessary to specify the order in which the directives are applied. The `priority` is used
5235 * to sort the directives before their `compile` functions get called. Priority is defined as a
5236 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5237 * are also run in priority order, but post-link functions are run in reverse order. The order
5238 * of directives with the same priority is undefined. The default priority is `0`.
5239 *
5240 * #### `terminal`
5241 * If set to true then the current `priority` will be the last set of directives
5242 * which will execute (any directives at the current priority will still execute
5243 * as the order of execution on same `priority` is undefined).
5244 *
5245 * #### `scope`
5246 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5247 * same element request a new scope, only one new scope is created. The new scope rule does not
5248 * apply for the root of the template since the root of the template always gets a new scope.
5249 *
5250 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5251 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5252 * when creating reusable components, which should not accidentally read or modify data in the
5253 * parent scope.
5254 *
5255 * The 'isolate' scope takes an object hash which defines a set of local scope properties
5256 * derived from the parent scope. These local properties are useful for aliasing values for
5257 * templates. Locals definition is a hash of local scope property to its source:
5258 *
5259 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5260 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5261 *   attribute name is assumed to be the same as the local name.
5262 *   Given `<widget my-attr="hello {{name}}">` and widget definition
5263 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5264 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5265 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5266 *   component scope).
5267 *
5268 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5269 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5270 *   name is specified then the attribute name is assumed to be the same as the local name.
5271 *   Given `<widget my-attr="parentModel">` and widget definition of
5272 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5273 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5274 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5275 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5276 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5277 *
5278 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5279 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5280 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5281 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5282 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5283 *   pass data from the isolated scope via an expression to the parent scope, this can be
5284 *   done by passing a map of local variable names and values into the expression wrapper fn.
5285 *   For example, if the expression is `increment(amount)` then we can specify the amount value
5286 *   by calling the `localFn` as `localFn({amount: 22})`.
5287 *
5288 *
5289 *
5290 * #### `controller`
5291 * Controller constructor function. The controller is instantiated before the
5292 * pre-linking phase and it is shared with other directives (see
5293 * `require` attribute). This allows the directives to communicate with each other and augment
5294 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5295 *
5296 * * `$scope` - Current scope associated with the element
5297 * * `$element` - Current element
5298 * * `$attrs` - Current attributes object for the element
5299 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5300 *    The scope can be overridden by an optional first argument.
5301 *   `function([scope], cloneLinkingFn)`.
5302 *
5303 *
5304 * #### `require`
5305 * Require another directive and inject its controller as the fourth argument to the linking function. The
5306 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5307 * injected argument will be an array in corresponding order. If no such directive can be
5308 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5309 *
5310 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5311 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5312 * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5313 * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
5314 *   `link` fn if not found.
5315 *
5316 *
5317 * #### `controllerAs`
5318 * Controller alias at the directive scope. An alias for the controller so it
5319 * can be referenced at the directive template. The directive needs to define a scope for this
5320 * configuration to be used. Useful in the case when directive is used as component.
5321 *
5322 *
5323 * #### `restrict`
5324 * String of subset of `EACM` which restricts the directive to a specific directive
5325 * declaration style. If omitted, the default (attributes only) is used.
5326 *
5327 * * `E` - Element name: `<my-directive></my-directive>`
5328 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5329 * * `C` - Class: `<div class="my-directive: exp;"></div>`
5330 * * `M` - Comment: `<!-- directive: my-directive exp -->`
5331 *
5332 *
5333 * #### `template`
5334 * HTML markup that may:
5335 * * Replace the contents of the directive's element (default).
5336 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
5337 * * Wrap the contents of the directive's element (if `transclude` is true).
5338 *
5339 * Value may be:
5340 *
5341 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
5342 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
5343 *   function api below) and returns a string value.
5344 *
5345 *
5346 * #### `templateUrl`
5347 * Same as `template` but the template is loaded from the specified URL. Because
5348 * the template loading is asynchronous the compilation/linking is suspended until the template
5349 * is loaded.
5350 *
5351 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5352 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5353 * a string value representing the url.  In either case, the template URL is passed through {@link
5354 * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5355 *
5356 *
5357 * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
5358 * specify what the template should replace. Defaults to `false`.
5359 *
5360 * * `true` - the template will replace the directive's element.
5361 * * `false` - the template will replace the contents of the directive's element.
5362 *
5363 * The replacement process migrates all of the attributes / classes from the old element to the new
5364 * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5365 * Directives Guide} for an example.
5366 *
5367 * #### `transclude`
5368 * compile the content of the element and make it available to the directive.
5369 * Typically used with {@link ng.directive:ngTransclude
5370 * ngTransclude}. The advantage of transclusion is that the linking function receives a
5371 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5372 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5373 * scope. This makes it possible for the widget to have private state, and the transclusion to
5374 * be bound to the parent (pre-`isolate`) scope.
5375 *
5376 * * `true` - transclude the content of the directive.
5377 * * `'element'` - transclude the whole element including any directives defined at lower priority.
5378 *
5379 * <div class="alert alert-warning">
5380 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
5381 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
5382 * Testing Transclusion Directives}.
5383 * </div>
5384 *
5385 * #### `compile`
5386 *
5387 * ```js
5388 *   function compile(tElement, tAttrs, transclude) { ... }
5389 * ```
5390 *
5391 * The compile function deals with transforming the template DOM. Since most directives do not do
5392 * template transformation, it is not used often. The compile function takes the following arguments:
5393 *
5394 *   * `tElement` - template element - The element where the directive has been declared. It is
5395 *     safe to do template transformation on the element and child elements only.
5396 *
5397 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5398 *     between all directive compile functions.
5399 *
5400 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5401 *
5402 * <div class="alert alert-warning">
5403 * **Note:** The template instance and the link instance may be different objects if the template has
5404 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5405 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5406 * should be done in a linking function rather than in a compile function.
5407 * </div>
5408
5409 * <div class="alert alert-warning">
5410 * **Note:** The compile function cannot handle directives that recursively use themselves in their
5411 * own templates or compile functions. Compiling these directives results in an infinite loop and a
5412 * stack overflow errors.
5413 *
5414 * This can be avoided by manually using $compile in the postLink function to imperatively compile
5415 * a directive's template instead of relying on automatic template compilation via `template` or
5416 * `templateUrl` declaration or manual compilation inside the compile function.
5417 * </div>
5418 *
5419 * <div class="alert alert-error">
5420 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5421 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5422 *   to the link function instead.
5423 * </div>
5424
5425 * A compile function can have a return value which can be either a function or an object.
5426 *
5427 * * returning a (post-link) function - is equivalent to registering the linking function via the
5428 *   `link` property of the config object when the compile function is empty.
5429 *
5430 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5431 *   control when a linking function should be called during the linking phase. See info about
5432 *   pre-linking and post-linking functions below.
5433 *
5434 *
5435 * #### `link`
5436 * This property is used only if the `compile` property is not defined.
5437 *
5438 * ```js
5439 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5440 * ```
5441 *
5442 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5443 * executed after the template has been cloned. This is where most of the directive logic will be
5444 * put.
5445 *
5446 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5447 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5448 *
5449 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5450 *     manipulate the children of the element only in `postLink` function since the children have
5451 *     already been linked.
5452 *
5453 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5454 *     between all directive linking functions.
5455 *
5456 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5457 *     element defines a controller. The controller is shared among all the directives, which allows
5458 *     the directives to use the controllers as a communication channel.
5459 *
5460 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5461 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5462 *     parameter of directive controllers.
5463 *     `function([scope], cloneLinkingFn)`.
5464 *
5465 *
5466 * #### Pre-linking function
5467 *
5468 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5469 * compiler linking function will fail to locate the correct elements for linking.
5470 *
5471 * #### Post-linking function
5472 *
5473 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5474 *
5475 * <a name="Attributes"></a>
5476 * ### Attributes
5477 *
5478 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5479 * `link()` or `compile()` functions. It has a variety of uses.
5480 *
5481 * accessing *Normalized attribute names:*
5482 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5483 * the attributes object allows for normalized access to
5484 *   the attributes.
5485 *
5486 * * *Directive inter-communication:* All directives share the same instance of the attributes
5487 *   object which allows the directives to use the attributes object as inter directive
5488 *   communication.
5489 *
5490 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5491 *   allowing other directives to read the interpolated value.
5492 *
5493 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5494 *   that contain interpolation (e.g. `src="{{bar}}
5494"`). Not only is this very efficient but it's also
5495 *   the only way to easily get the actual value because during the linking phase the interpolation
5496 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5497 *
5498 * ```js
5499 * function linkingFn(scope, elm, attrs, ctrl) {
5500 *   // get the attribute value
5501 *   console.log(attrs.ngModel);
5502 *
5503 *   // change the attribute
5504 *   attrs.$set('ngModel', 'new value');
5505 *
5506 *   // observe changes to interpolated attribute
5507 *   attrs.$observe('ngModel', function(value) {
5508 *     console.log('ngModel has changed value to ' + value);
5509 *   });
5510 * }
5511 * ```
5512 *
5513 * Below is an example using `$compileProvider`.
5514 *
5515 * <div class="alert alert-warning">
5516 * **Note**: Typically directives are registered with `module.directive`. The example below is
5517 * to illustrate how `$compile` works.
5518 * </div>
5519 *
5520 <example module="compileExample">
5521   <file name="index.html">
5522    <script>
5523      angular.module('compileExample', [], function($compileProvider) {
5524        // configure new 'compile' directive by passing a directive
5525        // factory function. The factory function injects the '$compile'
5526        $compileProvider.directive('compile', function($compile) {
5527          // directive factory creates a link function
5528          return function(scope, element, attrs) {
5529            scope.$watch(
5530              function(scope) {
5531                 // watch the 'compile' expression for changes
5532                return scope.$eval(attrs.compile);
5533              },
5534              function(value) {
5535                // when the 'compile' expression changes
5536                // assign it into the current DOM
5537                element.html(value);
5538
5539                // compile the new DOM and link it to the current
5540                // scope.
5541                // NOTE: we only compile .childNodes so that
5542                // we don't get into infinite loop compiling ourselves
5543                $compile(element.contents())(scope);
5544              }
5545            );
5546          };
5547        });
5548      })
5549      .controller('GreeterController', ['$scope', function($scope) {
5550        $scope.name = 'Angular';
5551        $scope.html = 'Hello {{name}}';
5552      }]);
5553    </script>
5554    <div ng-controller="GreeterController">
5555      <input ng-model="name"> <br>
5556      <textarea ng-model="html"></textarea> <br>
5557      <div compile="html"></div>
5558    </div>
5559   </file>
5560   <file name="protractor.js" type="protractor">
5561     it('should auto compile', function() {
5562       var textarea = $('textarea');
5563       var output = $('div[compile]');
5564       // The initial state reads 'Hello Angular'.
5565       expect(output.getText()).toBe('Hello Angular');
5566       textarea.clear();
5567       textarea.sendKeys('{{name}}!');
5568       expect(output.getText()).toBe('Angular!');
5569     });
5570   </file>
5571 </example>
5572
5573 *
5574 *
5575 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5576 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5577 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5578 *                 root element(s), not their children)
5579 * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5580 * (a DOM element/tree) to a scope. Where:
5581 *
5582 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5583 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5584 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5585 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5586 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5587 *
5588 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5589 *      * `scope` - is the current scope with which the linking function is working with.
5590 *
5591 * Calling the linking function returns the element of the template. It is either the original
5592 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5593 *
5594 * After linking the view is not updated until after a call to $digest which typically is done by
5595 * Angular automatically.
5596 *
5597 * If you need access to the bound view, there are two ways to do it:
5598 *
5599 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5600 *   before you send them to the compiler and keep this reference around.
5601 *   ```js
5602 *     var element = $compile('<p>{{total}}</p>')(scope);
5603 *   ```
5604 *
5605 * - if on the other hand, you need the element to be cloned, the view reference from the original
5606 *   example would not point to the clone, but rather to the original template that was cloned. In
5607 *   this case, you can access the clone via the cloneAttachFn:
5608 *   ```js
5609 *     var templateElement = angular.element('<p>{{total}}</p>'),
5610 *         scope = ....;
5611 *
5612 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5613 *       //attach the clone to DOM document at the right place
5614 *     });
5615 *
5616 *     //now we have reference to the cloned DOM via `clonedElement`
5617 *   ```
5618 *
5619 *
5620 * For information on how the compiler works, see the
5621 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5622 */
5623
5624var $compileMinErr = minErr('$compile');
5625
5626/**
5627 * @ngdoc provider
5628 * @name $compileProvider
5629 * @kind function
5630 *
5631 * @description
5632 */
vendor: 4,560 bytes, lines 5633-5741
5633$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5634function $CompileProvider($provide, $$sanitizeUriProvider) {
5635  var hasDirectives = {},
5636      Suffix = 'Directive',
5637      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
5638      CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
5639
5640  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5641  // The assumption is that future DOM event attribute names will begin with
5642  // 'on' and be composed of only English letters.
5643  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5644
5645  /**
5646   * @ngdoc method
5647   * @name $compileProvider#directive
5648   * @kind function
5649   *
5650   * @description
5651   * Register a new directive with the compiler.
5652   *
5653   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5654   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5655   *    names and the values are the factories.
5656   * @param {Function|Array} directiveFactory An injectable directive factory function. See
5657   *    {@link guide/directive} for more info.
5658   * @returns {ng.$compileProvider} Self for chaining.
5659   */
5660   this.directive = function registerDirective(name, directiveFactory) {
5661    assertNotHasOwnProperty(name, 'directive');
5662    if (isString(name)) {
5663      assertArg(directiveFactory, 'directiveFactory');
5664      if (!hasDirectives.hasOwnProperty(name)) {
5665        hasDirectives[name] = [];
5666        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5667          function($injector, $exceptionHandler) {
5668            var directives = [];
5669            forEach(hasDirectives[name], function(directiveFactory, index) {
5670              try {
5671                var directive = $injector.invoke(directiveFactory);
5672                if (isFunction(directive)) {
5673                  directive = { compile: valueFn(directive) };
5674                } else if (!directive.compile && directive.link) {
5675                  directive.compile = valueFn(directive.link);
5676                }
5677                directive.priority = directive.priority || 0;
5678                directive.index = index;
5679                directive.name = directive.name || name;
5680                directive.require = directive.require || (directive.controller && directive.name);
5681                directive.restrict = directive.restrict || 'A';
5682                directives.push(directive);
5683              } catch (e) {
5684                $exceptionHandler(e);
5685              }
5686            });
5687            return directives;
5688          }]);
5689      }
5690      hasDirectives[name].push(directiveFactory);
5691    } else {
5692      forEach(name, reverseParams(registerDirective));
5693    }
5694    return this;
5695  };
5696
5697
5698  /**
5699   * @ngdoc method
5700   * @name $compileProvider#aHrefSanitizationWhitelist
5701   * @kind function
5702   *
5703   * @description
5704   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5705   * urls during a[href] sanitization.
5706   *
5707   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5708   *
5709   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5710   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5711   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5712   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5713   *
5714   * @param {RegExp=} regexp New regexp to whitelist urls with.
5715   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5716   *    chaining otherwise.
5717   */
5718  this.aHrefSanitizationWhitelist = function(regexp) {
5719    if (isDefined(regexp)) {
5720      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5721      return this;
5722    } else {
5723      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5724    }
5725  };
5726
5727
5728  /**
5729   * @ngdoc method
5730   * @name $compileProvider#imgSrcSanitizationWhitelist
5731   * @kind function
5732   *
5733   * @description
5734   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5735   * urls during img[src] sanitization.
5736   *
5737   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5738   *
5739   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5740   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5741   * regular expression. If a match is found, the original url is 
5741written into the dom. Otherwise,
5742   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5743   *
5744   * @param {RegExp=} regexp New regexp to whitelist urls with.
5745   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5746   *    chaining otherwise.
5747   */
5748  this.imgSrcSanitizationWhitelist = function(regexp) {
5749    if (isDefined(regexp)) {
5750      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5751      return this;
5752    } else {
5753      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5754    }
5755  };
5756
5757  this.$get = [
5758            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5759            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5760    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5761             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5762
5763    var Attributes = function(element, attr) {
5764      this.$$element = element;
5765      this.$attr = attr || {};
5766    };
5767
5768    Attributes.prototype = {
5769      $normalize: directiveNormalize,
5770
5771
5772      /**
5773       * @ngdoc method
5774       * @name $compile.directive.Attributes#$addClass
5775       * @kind function
5776       *
5777       * @description
5778       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5779       * are enabled then an animation will be triggered for the class addition.
5780       *
5781       * @param {string} classVal The className value that will be added to the element
5782       */
5783      $addClass : function(classVal) {
5784        if(classVal && classVal.length > 0) {
5785          $animate.addClass(this.$$element, classVal);
5786        }
5787      },
5788
5789      /**
5790       * @ngdoc method
5791       * @name $compile.directive.Attributes#$removeClass
5792       * @kind function
5793       *
5794       * @description
5795       * Removes the CSS class value specified by the classVal parameter from the element. If
5796       * animations are enabled then an animation will be triggered for the class removal.
5797       *
5798       * @param {string} classVal The className value that will be removed from the element
5799       */
5800      $removeClass : function(classVal) {
5801        if(classVal && classVal.length > 0) {
5802          $animate.removeClass(this.$$element, classVal);
5803        }
5804      },
5805
5806      /**
5807       * @ngdoc method
5808       * @name $compile.directive.Attributes#$updateClass
5809       * @kind function
5810       *
5811       * @description
5812       * Adds and removes the appropriate CSS class values to the element based on the difference
5813       * between the new and old CSS class values (specified as newClasses and oldClasses).
5814       *
5815       * @param {string} newClasses The current CSS className value
5816       * @param {string} oldClasses The former CSS className value
5817       */
5818      $updateClass : function(newClasses, oldClasses) {
5819        var toAdd = tokenDifference(newClasses, oldClasses);
5820        var toRemove = tokenDifference(oldClasses, newClasses);
5821
5822        if(toAdd.length === 0) {
5823          $animate.removeClass(this.$$element, toRemove);
5824        } else if(toRemove.length === 0) {
5825          $animate.addClass(this.$$element, toAdd);
5826        } else {
5827          $animate.setClass(this.$$element, toAdd, toRemove);
5828        }
5829      },
5830
5831      /**
5832       * Set a normalized attribute on the element in a way such that all directives
5833       * can share the attribute. This function properly handles boolean attributes.
5834       * @param {string} key Normalized key. (ie ngAttribute)
5835       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5836       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5837       *     Defaults to true.
5838       * @param {string=} attrName Optional none normalized name. Defaults to key.
5839       */
5840      $set: function(key, value, writeAttr, attrName) {
5841        // TODO: decide whether or not to throw an error if "class"
5842        //is set through this function since it may cause $updateClass to
5843        //become unstable.
5844
5845        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5846            normalizedVal,
5847            nodeName;
5848
5849        if (booleanKey) {
5850          this.$$element.prop(key, value);
5851          attrName = booleanKey;
5852        }
5853
5854        this[key] = value;
5855
5856        // translate normalized key to actual key
5857        if (attrName) {
5858          this.$attr[key] = attrName;
5859        } else {
5860          attrName = this.$attr[key];
5861          if (!attrName) {
5862            this.$attr[key] = attrName = snake_case(key, '-');
5863          }
5864        }
5865
5866        nodeName = nodeName_(this.$$element);
5867
5868        // sanitize a[href] and img[src] values
5869        if ((nodeName === 'A' && key === 'href') ||
5870            (nodeName === 'IMG' && key === 'src')) {
5871          this[key] = value = $$sanitizeUri(value, key === 'src');
5872        }
5873
5874        if (writeAttr !== false) {
5875          if (value === null || value === undefined) {
5876            this.$$element.removeAttr(attrName);
5877          } else {
5878            this.$$element.attr(attrName, value);
5879          }
5880        }
5881
5882        // fire observers
5883        var $$observers = this.$$observers;
5884        $$observers && forEach($$observers[key], function(fn) {
5885          try {
5886            fn(value);
5887          } catch (e) {
5888            $exceptionHandler(e);
5889          }
5890        });
5891      },
5892
5893
5894      /**
5895       * @ngdoc method
5896       * @name $compile.directive.Attributes#$observe
5897       * @kind function
5898       *
5899       * @description
5900       * Observes an interpolated attribute.
5901       *
5902       * The observer function will be invoked once during the next `$digest` following
5903       * compilation. The observer is then invoked whenever the interpolated value
5904       * changes.
5905       *
5906       * @param {string} key Normalized key. (ie ngAttribute) .
5907       * @param {function(interpolatedValue)} fn Function that will be called whenever
5908                the interpolated value of the attribute changes.
5909       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5910       * @returns {function()} the `fn` parameter.
5911       */
5912      $observe: function(key, fn) {
5913        var attrs = this,
5914            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5915            listeners = ($$observers[key] || ($$observers[key] = []));
5916
5917        listeners.push(fn);
5918        $rootScope.$evalAsync(function() {
5919          if (!listeners.$$inter) {
5920            // no one registered attribute interpolation function, so lets call it manually
5921            fn(attrs[key]);
5922          }
5923        });
5924        return fn;
5925      }
5926    };
5927
5928    var startSymbol = $interpolate.startSymbol(),
5929        endSymbol = $interpolate.endSymbol(),
5930        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5931            ? identity
5932            : function denormalizeTemplate(template) {
5933              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5934        },
5935        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5936
5937
5938    return compile;
5939
5940    //================================
5941
5942    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5943                        previousCompileContext) {
5944      if (!($compileNodes instanceof jqLite)) {
5945        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5946        // modify it.
5947        $compileNodes = jqLite($compileNodes);
5948      }
5949      // We can not compile top level text elements since text nodes can be merged and we will
5950      // not be able to attach scope data to them, so we will wrap them in <span>
5951      forEach($compileNodes, function(node, index){
5952        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5953          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5954        }
5955      });
5956      var compositeLinkFn =
5957              compileNodes($compileNodes, transcludeFn, $compileNodes,
5958                           maxPriority, ignoreDirective, previousCompileContext);
5959      safeAddClass($compileNodes, 'ng-scope');
5960      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
5961        assertArg(scope, 'scope');
5962        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5963        // and sometimes changes the structure of the DOM.
5964        var $linkNode = cloneConnectFn
5965          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5966          : $compileNodes;
5967
5968        forEach(transcludeControllers, function(instance, name) {
5969          $linkNode.data('$' + name + 'Controller', instance);
5970        });
5971
5972        // Attach scope only to non-text nodes.
5973        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5974          var node = $linkNode[i],
5975              nodeType = node.nodeType;
5976          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5977            $linkNode.eq(i).data('$scope', scope);
5978          }
5979        }
5980
5981        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5982        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
5983        return $linkNode;
5984      };
5985    }
5986
5987    function safeAddClass($element, className) {
vendor: 4,887 bytes, lines 5988-6098
5988      try {
5989        $element.addClass(className);
5990      } catch(e) {
5991        // ignore, since it means that we are trying to set class on
5992        // SVG element, where class name is read-only.
5993      }
5994    }
5995
5996    /**
5997     * Compile function matches each node in nodeList against the directives. Once all directives
5998     * for a particular node are collected their compile functions are executed. The compile
5999     * functions return values - the linking functions - are combined into a composite linking
6000     * function, which is the a linking function for the node.
6001     *
6002     * @param {NodeList} nodeList an array of nodes or NodeList to compile
6003     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6004     *        scope argument is auto-generated to the new child of the transcluded parent scope.
6005     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
6006     *        the rootElement must be set the jqLite collection of the compile root. This is
6007     *        needed so that the jqLite collection items can be replaced with widgets.
6008     * @param {number=} maxPriority Max directive priority.
6009     * @returns {Function} A composite linking function of all of the matched directives or null.
6010     */
6011    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
6012                            previousCompileContext) {
6013      var linkFns = [],
6014          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
6015
6016      for (var i = 0; i < nodeList.length; i++) {
6017        attrs = new Attributes();
6018
6019        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
6020        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
6021                                        ignoreDirective);
6022
6023        nodeLinkFn = (directives.length)
6024            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
6025                                      null, [], [], previousCompileContext)
6026            : null;
6027
6028        if (nodeLinkFn && nodeLinkFn.scope) {
6029          safeAddClass(attrs.$$element, 'ng-scope');
6030        }
6031
6032        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
6033                      !(childNodes = nodeList[i].childNodes) ||
6034                      !childNodes.length)
6035            ? null
6036            : compileNodes(childNodes,
6037                 nodeLinkFn ? (
6038                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
6039                     && nodeLinkFn.transclude) : transcludeFn);
6040
6041        linkFns.push(nodeLinkFn, childLinkFn);
6042        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
6043        //use the previous context only for the first element in the virtual group
6044        previousCompileContext = null;
6045      }
6046
6047      // return a linking function if we have found anything, null otherwise
6048      return linkFnFound ? compositeLinkFn : null;
6049
6050      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
6051        var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
6052
6053        // copy nodeList so that linking doesn't break due to live list updates.
6054        var nodeListLength = nodeList.length,
6055            stableNodeList = new Array(nodeListLength);
6056        for (i = 0; i < nodeListLength; i++) {
6057          stableNodeList[i] = nodeList[i];
6058        }
6059
6060        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
6061          node = stableNodeList[n];
6062          nodeLinkFn = linkFns[i++];
6063          childLinkFn = linkFns[i++];
6064
6065          if (nodeLinkFn) {
6066            if (nodeLinkFn.scope) {
6067              childScope = scope.$new();
6068              jqLite.data(node, '$scope', childScope);
6069            } else {
6070              childScope = scope;
6071            }
6072
6073            if ( nodeLinkFn.transcludeOnThisElement ) {
6074              childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
6075
6076            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
6077              childBoundTranscludeFn = parentBoundTranscludeFn;
6078
6079            } else if (!parentBoundTranscludeFn && transcludeFn) {
6080              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
6081
6082            } else {
6083              childBoundTranscludeFn = null;
6084            }
6085
6086            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
6087
6088          } else if (childLinkFn) {
6089            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
6090          }
6091        }
6092      }
6093    }
6094
6095    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
6096
6097      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
6098        var scopeCreated = false;
6099
6100        if (!transcludedScope) {
6101          transcludedScope = scope.$new();
6102          transcludedScope.$$transcluded = true;
6103          scopeCreated = true;
6104        }
6105
6106        var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
6107        if (scopeCreated) {
6108          clone.on('$destroy', function() { transcludedScope.$destroy(); });
6109        }
6110        return clone;
6111      };
6112
6113      return boundTranscludeFn;
6114    }
6115
6116    /**
6117     * Looks for directives on the given node and adds them to the directive collection which is
6118     * sorted.
6119     *
6120     * @param node Node to search.
6121     * @param directives An array to which the directives are added to. This array is sorted before
6122     *        the function returns.
6123     * @param attrs The shared attrs object which is used to populate the normalized attributes.
6124     * @param {number=} maxPriority Max directive priority.
6125     */
6126    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6127      var nodeType = node.nodeType,
6128          attrsMap = attrs.$attr,
6129          match,
6130          className;
6131
6132      switch(nodeType) {
6133        case 1: /* Element */
6134          // use the node name: <directive>
6135          addDirective(directives,
6136              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6137
6138          // iterate over the attributes
6139          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
6140                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6141            var attrStartName = false;
6142            var attrEndName = false;
6143
6144            attr = nAttrs[j];
6145            if (!msie || msie >= 8 || attr.specified) {
6146              name = attr.name;
6147              value = trim(attr.value);
6148
6149              // support ngAttr attribute binding
6150              ngAttrName = directiveNormalize(name);
6151              if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
6152                name = snake_case(ngAttrName.substr(6), '-');
6153              }
6154
6155              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6156              if (ngAttrName === directiveNName + 'Start') {
6157                attrStartName = name;
6158                attrEndName = name.substr(0, name.length - 5) + 'end';
6159                name = name.substr(0, name.length - 6);
6160              }
6161
6162              nName = directiveNormalize(name.toLowerCase());
6163              attrsMap[nName] = name;
6164              if (isNgAttr || !attrs.hasOwnProperty(nName)) {
6165                  attrs[nName] = value;
6166                  if (getBooleanAttrName(node, nName)) {
6167                    attrs[nName] = true; // presence means true
6168                  }
6169              }
6170              addAttrInterpolateDirective(node, directives, value, nName);
6171              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6172                            attrEndName);
6173            }
6174          }
6175
6176          // use class as directive
6177          className = node.className;
6178          if (isString(className) && className !== '') {
6179            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6180              nName = directiveNormalize(match[2]);
6181              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6182                attrs[nName] = trim(match[3]);
6183              }
6184              className = className.substr(match.index + match[0].length);
6185            }
6186          }
6187          break;
6188        case 3: /* Text Node */
6189          addTextInterpolateDirective(directives, node.nodeValue);
6190          break;
6191        case 8: /* Comment */
6192          try {
6193            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6194            if (match) {
6195              nName = directiveNormalize(match[1]);
6196              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6197                attrs[nName] = trim(match[2]);
6198              }
6199            }
6200          } catch (e) {
6201            // turns out that under some circumstances IE9 throws errors when one attempts to read
6202            // comment's node value.
6203            // Just ignore it and continue. (Can't seem to reproduce in test case.)
6204          }
6205          break;
6206      }
6207
6208      directives.sort(byPriority);
6209      return directives;
6210    }
6211
6212    /**
6213     * Given a node with an directive-start it collects all of the siblings until it finds
6214     * directive-end.
6215     * @param node
6216     * @param attrStart
6217     * @param attrEnd
6218     * @returns {*}
6219     */
6220    function groupScan(node, attrStart, attrEnd) {
6221      var nodes = [];
6222      var depth = 0;
6223      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6224        var startNode = node;
6225        do {
6226          if (!node) {
6227            throw $compileMinErr('uterdir',
6228                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6229                      attrStart, attrEnd);
6230          }
6231          if (node.nodeType == 1 /** Element **/) {
6232            if (node.hasAttribute(attrStart)) depth++;
6233            if (node.hasAttribute(attrEnd)) depth--;
6234          }
6235          nodes.push(node);
6236          node = node.nextSibling;
6237        } while (depth > 0);
6238      } else {
6239        nodes.push(node);
6240      }
6241
6242      return jqLite(nodes);
6243    }
6244
6245    /**
6246     * Wrapper for linking function which converts normal linking function into a grouped
6247     * linking function.
6248     * @param linkFn
6249     * @param attrStart
6250     * @param attrEnd
6251     * @returns {Function}
6252     */
6253    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6254      return function(scope, element, attrs, controllers, transcludeFn) {
6255        element = groupScan(element[0], attrStart, attrEnd);
6256        return linkFn(scope, element, attrs, controllers, transcludeFn);
6257      };
6258    }
6259
6260    /**
6261     * Once the directives have been collected, their compile functions are executed. This method
6262     * is responsible for inlining directive templates as well as terminating the application
6263     * of the directives if the terminal directive has been reached.
6264     *
6265     * @param {Array} directives Array of collected directives to execute their compile function.
6266     *        this needs to be pre-sorted by priority order.
6267     * @param {Node} compileNode The raw DOM node to apply the compile functions to
6268     * @param {Object} templateAttrs The shared attribute function
6269     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6270     *                                                  scope argument is auto-generated to the new
6271     *                                                  child of the transcluded parent scope.
6272     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6273     *                              argument has the root jqLite array so that we can replace nodes
6274     *                              on it.
6275     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6276     *                                           compiling the transclusion.
6277     * @param {Array.<Function>} preLinkFns
6278     * @param {Array.<Function>} postLinkFns
6279     * @param {Object} previousCompileContext Context used for previous compilation of the current
6280     *                                        node
6281     * @returns {Function} linkFn
6282     */
6283    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
6284                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
6285                                   previousCompileContext) {
6286      previousCompileContext = previousCompileContext || {};
6287
6288      var terminalPriority = -Number.MAX_VALUE,
6289          newScopeDirective,
6290          controllerDirectives = previousCompileContext.controllerDirectives,
6291          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6292          templateDirective = previousCompileContext.templateDirective,
6293          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6294          hasTranscludeDirective = false,
6295          hasTemplate = false,
6296          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6297          $compileNode = templateAttrs.$$element = jqLite(compileNode),
6298          directive,
6299          directiveName,
6300          $template,
6301          replaceDirective = originalReplaceDirective,
6302          childTranscludeFn = transcludeFn,
6303          linkFn,
6304          directiveValue;
6305
6306      // executes all directives on the current element
6307      for(var i = 0, ii = directives.length; i < ii; i++) {
6308        directive = directives[i];
6309        var attrStart = directive.$$start;
6310        var attrEnd = directive.$$end;
6311
6312        // collect multiblock sections
6313        if (attrStart) {
6314          $compileNode = groupScan(compileNode, attrStart, attrEnd);
6315        }
6316        $template = undefined;
6317
6318        if (terminalPriority > directive.priority) {
6319          break; // prevent further processing of directives
6320        }
6321
6322        if (directiveValue = directive.scope) {
6323          newScopeDirective = newScopeDirective || directive;
6324
6325          // skip the check for directives with async templates, we'll check the derived sync
6326          // directive when the template arrives
6327          if (!directive.templateUrl) {
6328            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6329                              $compileNode);
6330            if (isObject(directiveValue)) {
6331              newIsolateScopeDirective = directive;
6332            }
6333          }
6334        }
6335
6336        directiveName = directive.name;
6337
6338        if (!directive.templateUrl && directive.controller) {
6339          directiveValue = directive.controller;
6340          controllerDirectives = controllerDirectives || {};
6341          assertNoDuplicate("'" + directiveName + "' controller",
6342              controllerDirectives[directiveName], directive, $compileNode);
6343          controllerDirectives[directiveName] = directive;
6344        }
6345
6346        if (directiveValue = directive.transclude) {
6347          hasTranscludeDirective = true;
6348
6349          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6350          // This option should only be used by directives that know how to safely handle element transclusion,
6351          // where the transcluded nodes are added or replaced after linking.
6352          if (!directive.$$tlb) {
6353            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6354            nonTlbTranscludeDirective = directive;
6355          }
6356
6357          if (directiveValue == 'element') {
6358            hasElementTranscludeDirective = true;
6359            terminalPriority = directive.priority;
6360            $template = $compileNode;
6361            $compileNode = templateAttrs.$$element =
6362                jqLite(document.createComment(' ' + directiveName + ': ' +
6363                                              templateAttrs[directiveName] + ' '));
6364            compileNode = $compileNode[0];
6365            replaceWith(jqCollection, sliceArgs($template), compileNode);
6366
6367            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6368                                        replaceDirective && replaceDirective.name, {
6369                                          // Don't pass in:
6370                                          // - controllerDirectives - otherwise we'll create duplicates controllers
6371                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 4,603 bytes, lines 6371-6478
6371ining templates with
6372                                          //   element transclusion doesn't make sense.
6373                                          //
6374                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6375                                          // on the same element more than once.
6376                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
6377                                        });
6378          } else {
6379            $template = jqLite(jqLiteClone(compileNode)).contents();
6380            $compileNode.empty(); // clear contents
6381            childTranscludeFn = compile($template, transcludeFn);
6382          }
6383        }
6384
6385        if (directive.template) {
6386          hasTemplate = true;
6387          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6388          templateDirective = directive;
6389
6390          directiveValue = (isFunction(directive.template))
6391              ? directive.template($compileNode, templateAttrs)
6392              : directive.template;
6393
6394          directiveValue = denormalizeTemplate(directiveValue);
6395
6396          if (directive.replace) {
6397            replaceDirective = directive;
6398            if (jqLiteIsTextNode(directiveValue)) {
6399              $template = [];
6400            } else {
6401              $template = jqLite(trim(directiveValue));
6402            }
6403            compileNode = $template[0];
6404
6405            if ($template.length != 1 || compileNode.nodeType !== 1) {
6406              throw $compileMinErr('tplrt',
6407                  "Template for directive '{0}' must have exactly one root element. {1}",
6408                  directiveName, '');
6409            }
6410
6411            replaceWith(jqCollection, $compileNode, compileNode);
6412
6413            var newTemplateAttrs = {$attr: {}};
6414
6415            // combine directives from the original node and from the template:
6416            // - take the array of directives for this element
6417            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6418            // - collect directives from the template and sort them by priority
6419            // - combine directives as: processed + template + unprocessed
6420            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6421            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6422
6423            if (newIsolateScopeDirective) {
6424              markDirectivesAsIsolate(templateDirectives);
6425            }
6426            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6427            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6428
6429            ii = directives.length;
6430          } else {
6431            $compileNode.html(directiveValue);
6432          }
6433        }
6434
6435        if (directive.templateUrl) {
6436          hasTemplate = true;
6437          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6438          templateDirective = directive;
6439
6440          if (directive.replace) {
6441            replaceDirective = directive;
6442          }
6443
6444          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6445              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
6446                controllerDirectives: controllerDirectives,
6447                newIsolateScopeDirective: newIsolateScopeDirective,
6448                templateDirective: templateDirective,
6449                nonTlbTranscludeDirective: nonTlbTranscludeDirective
6450              });
6451          ii = directives.length;
6452        } else if (directive.compile) {
6453          try {
6454            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6455            if (isFunction(linkFn)) {
6456              addLinkFns(null, linkFn, attrStart, attrEnd);
6457            } else if (linkFn) {
6458              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6459            }
6460          } catch (e) {
6461            $exceptionHandler(e, startingTag($compileNode));
6462          }
6463        }
6464
6465        if (directive.terminal) {
6466          nodeLinkFn.terminal = true;
6467          terminalPriority = Math.max(terminalPriority, directive.priority);
6468        }
6469
6470      }
6471
6472      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6473      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
6474      nodeLinkFn.templateOnThisElement = hasTemplate;
6475      nodeLinkFn.transclude = childTranscludeFn;
6476
6477      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6478
6479      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6480      return nodeLinkFn;
6481
6482      ////////////////////
6483
6484      function addLinkFns(pre, post, attrStart, attrEnd) {
6485        if (pre) {
6486          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6487          pre.require = directive.require;
6488          pre.directiveName = directiveName;
6489          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6490            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6491          }
6492          preLinkFns.push(pre);
6493        }
6494        if (post) {
6495          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6496          post.require = directive.require;
6497          post.directiveName = directiveName;
6498          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6499            post = cloneAndAnnotateFn(post, {isolateScope: true});
6500          }
6501          postLinkFns.push(post);
6502        }
6503      }
6504
6505
6506      function getControllers(directiveName, require, $element, elementControllers) {
6507        var value, retrievalMethod = 'data', optional = false;
6508        if (isString(require)) {
6509          while((value = require.charAt(0)) == '^' || value == '?') {
6510            require = require.substr(1);
6511            if (value == '^') {
6512              retrievalMethod = 'inheritedData';
6513            }
6514            optional = optional || value == '?';
6515          }
6516          value = null;
6517
6518          if (elementControllers && retrievalMethod === 'data') {
6519            value = elementControllers[require];
6520          }
6521          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6522
6523          if (!value && !optional) {
6524            throw $compileMinErr('ctreq',
6525                "Controller '{0}', required by directive '{1}', can't be found!",
6526                require, directiveName);
6527          }
6528          return value;
6529        } else if (isArray(require)) {
6530          value = [];
6531          forEach(require, function(require) {
6532            value.push(getControllers(directiveName, require, $element, elementControllers));
6533          });
6534        }
6535        return value;
6536      }
6537
6538
6539      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6540        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6541
6542        attrs = (compileNode === linkNode)
6543          ? templateAttrs
6544          : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6545        $element = attrs.$$element;
6546
6547        if (newIsolateScopeDirective) {
6548          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6549
6550          isolateScope = scope.$new(true);
6551
6552          if (templateDirective && (templateDirective === newIsolateScopeDirective ||
6553              templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6554            $element.data('$isolateScope', isolateScope);
6555          } else {
6556            $element.data('$isolateScopeNoTemplate', isolateScope);
6557          }
6558
6559
6560
6561          safeAddClass($element, 'ng-isolate-scope');
6562
6563          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6564            var match = definition.match(LOCAL_REGEXP) || [],
6565                attrName = match[3] || scopeName,
6566                optional = (match[2] == '?'),
6567                mode = match[1], // @, =, or &
6568                lastValue,
6569                parentGet, parentSet, compare;
6570
6571            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6572
6573            switch (mode) {
6574
6575              case '@':
6576                attrs.$observe(attrName, function(value) {
6577                  isolateScope[scopeName] = value;
6578                });
6579                attrs.$$observers[attrName].$$scope = scope;
6580                if( attrs[attrName] ) {
6581                  // If the attribute has been provided then we trigger an interpolation to ensure
6582                  // the value is there for use in the link fn
6583                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6584                }
6585                break;
6586
6587              case '=':
6588                if (optional && !attrs[attrName]) {
6589                  return;
6590                }
6591                parentGet = $parse(attrs[attrName]);
6592                if (parentGet.literal) {
6593                  compare = equals;
6594                } else {
6595                  compare = function(a,b) { return a === b || (a !== a && b !== b); };
6596                }
6597                parentSet = parentGet.assign || function() {
6598                  // reset the change, or we will throw this exception on every $digest
6599                  lastValue = isolateScope[scopeName] = parentGet(scope);
6600                  throw $compileMinErr('nonassign',
6601                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6602                      attrs[attrName], newIsolateScopeDirective.name);
6603                };
6604                lastValue = isolateScope[scopeName] = parentGet(scope);
6605                isolateScope.$watch(function parentValueWatch() {
6606                  var parentValue = parentGet(scope);
6607                  if (!compare(parentValue, isolateScope[scopeName])) {
6608                    // we are out of sync and need to copy
6609                    if (!compare(parentValue, lastValue)) {
6610                      // parent changed and it has precedence
6611                      isolateScope[scopeName] = parentValue;
6612                    } else {
6613                      // if the parent can be assigned then do so
6614                      parentSet(scope, parentValue = isolateScope[scopeName]);
6615                    }
6616                  }
6617                  return lastValue = parentValue;
6618                }, null, parentGet.literal);
6619                break;
6620
6621              case '&':
6622                parentGet = $parse(attrs[attrName]);
6623                isolateScope[scopeName] = function(locals) {
6624                  return parentGet(scope, locals);
6625                };
6626                break;
6627
6628              default:
6629                throw $compileMinErr('iscp',
6630                    "Invalid isolate scope definition for directive '{0}'." +
6631                    " Definition: {... {1}: '{2}' ...}",
6632                    newIsolateScopeDirective.name, scopeName, definition);
6633            }
6634          });
6635        }
6636        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6637        if (controllerDirectives) {
6638          forEach(controllerDirectives, function(directive) {
6639            var locals = {
6640              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6641              $element: $element,
6642              $attrs: attrs,
6643              $transclude: transcludeFn
6644            }, controllerInstance;
6645
6646            controller = directive.controller;
6647            if (controller == '@') {
6648              controller = attrs[directive.name];
6649            }
6650
6651            controllerInstance = $controller(controller, locals);
6652            // For directives with element transclusion the element is a comment,
6653            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6654            // clean up (http://bugs.jquery.com/ticket/8335).
6655            // Instead, we save the controllers for the element in a local hash and attach to .data
6656            // later, once we have the actual element.
6657            elementControllers[directive.name] = controllerInstance;
6658            if (!hasElementTranscludeDirective) {
6659              $element.data('$' + directive.name + 'Controller', controllerInstance);
6660            }
6661
6662            if (directive.controllerAs) {
6663              locals.$scope[directive.controllerAs] = controllerInstance;
6664            }
6665          });
6666        }
6667
6668        // PRELINKING
6669        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6670          try {
6671            linkFn = preLinkFns[i];
6672            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6673                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6674          } catch (e) {
6675            $exceptionHandler(e, startingTag($element));
6676          }
6677        }
6678
6679        // RECURSION
6680        // We only pass the isolate scope, if the isolate directive has a template,
6681        // otherwise the child elements do not belong to the isolate directive.
6682        var scopeToChild = scope;
6683        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6684          scopeToChild = isolateScope;
6685        }
6686        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6687
6688        // POSTLINKING
6689        for(i = postLinkFns.length - 1; i >= 0; i--) {
6690          try {
6691            linkFn = postLinkFns[i];
6692            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6693                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6694          } catch (e) {
6695            $exceptionHandler(e, startingTag($element));
6696          }
6697        }
6698
6699        // This is the function that is injected as `$transclude`.
6700        function controllersBoundTransclude(scope, cloneAttachFn) {
6701          var transcludeControllers;
6702
6703          // no scope passed
6704          if (arguments.length < 2) {
6705            cloneAttachFn = scope;
6706            scope = undefined;
6707          }
6708
6709          if (hasElementTranscludeDirective) {
6710            transcludeControllers = elementControllers;
6711          }
6712
6713          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6714        }
6715      }
6716    }
6717
6718    function markDirectivesAsIsolate(directives) {
6719      // mark all directives as needing isolate scope.
6720      for (var j = 0, jj = directives.length; j < jj; j++) {
6721        directives[j] = inherit(directives[j], {$$isolateScope: true});
6722      }
6723    }
6724
6725    /**
6726     * looks up the directive and decorates it with exception handling and proper parameters. We
6727     * call this the boundDirective.
6728     *
6729     * @param {string} name name of the directive to look up.
6730     * @param {string} location The directive must be found in specific format.
6731     *   String containing any of theses characters:
6732     *
6733     *   * `E`: element name
6734     *   * `A': attribute
6735     *   * `C`: class
6736     *   * `M`: comment
6737     * @returns {boolean} true if directive was added.
6738     */
6739    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6740                          endAttrName) {
6741      if (name === ignoreDirective) return null;
6742      var match = null;
6743      if (hasDirectives.hasOwnProperty(name)) {
6744        for(var directive, directives = $injector.get(name + Suffix),
6745            i = 0, ii = directives.length; i<ii; i++) {
6746          try {
6747            directive = directives[i];
6748            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6749                 directive.restrict.indexOf(location) != -1) {
6750              if (startAttrName) {
6751                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6752              }
6753              tDirectives.push(directive);
6754              match = directive;
6755            }
6756          } catch(e) { $exceptionHandler(e); }
6757        }
6758      }
6759      return match;
6760    }
6761
6762
6763    /**
6764     * When the element is replaced with HTML template then the new attributes
6765     * on the template need to be merged with the existing attributes in the DOM.
6766     * The desired effect is to have both of the attributes present.
6767     *
6768     * @param {object} dst destination attributes (original DOM)
6769     * @param {object} src source attributes (from the directive template)
6770     */
6771    function mergeTemplateAttributes(dst, src) {
6772      var srcAttr = src.$attr,
6773          dstAttr = dst.$attr,
6774          $element = dst.$$element;
6775
6776      // reapply the old attributes to the new element
6777      forEach(dst, function(value, key) {
6778        if (key.charAt(0) != '$') {
6779          if (src[key] && src[key] !== value) {
6780            value += (key === 'style' ? ';' : ' ') + src[key];
6781          }
6782          dst.$set(key, value, true, srcAttr[key]);
6783        }
6784      });
6785
6786      // copy the new attributes on the old attrs object
6787      forEach(src, function(value, key) {
6788        if (key == 'class') {
6789          safeAddClass($element, value);
6790          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6791        } else if (key == 'style') {
6792          $element.attr('style', $element.attr('style') + ';' + value);
6793          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6794          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6795          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6796          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6797        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6798          dst[key] = value;
6799          dstAttr[key] = srcAttr[key];
6800        }
6801      });
6802    }
6803
6804
6805    function compileTemplateUrl(directives, $compileNode, tAttrs,
6806        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6807      var linkQueue = [],
6808          afterTemplateNodeLinkFn,
6809          afterTemplateChildLinkFn,
6810          beforeTemplateCompileNode = $compileNode[0],
6811          origAsyncDirective = directives.shift(),
6812          // The fact that we have to copy and patch the directive seems wrong!
6813          derivedSyncDirective = extend({}, origAsyncDirective, {
6814            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6815          }),
6816          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6817              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
6818              : origAsyncDirective.templateUrl;
6819
6820      $compileNode.empty();
6821
6822      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6823        success(function(content) {
6824          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6825
6826          content = denormalizeTemplate(content);
6827
6828          if (origAsyncDirective.replace) {
6829            if (jqLiteIsTextNode(content)) {
6830              $template = [];
6831            } else {
6832              $template = jqLite(trim(content));
6833            }
6834            compileNode = $template[0];
6835
6836            if ($template.length != 1 || compileNode.nodeType !== 1) {
6837              throw $compileMinErr('tplrt',
6838                  "Template for directive '{0}' must have exactly one root element. {1}",
6839                  origAsyncDirective.name, templateUrl);
6840            }
6841
6842            tempTemplateAttrs = {$attr: {}};
6843            replaceWith($rootElement, $compileNode, compileNode);
6844            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6845
6846            if (isObject(origAsyncDirective.scope)) {
6847              markDirectivesAsIsolate(templateDirectives);
6848            }
6849            directives = templateDirectives.concat(directives);
6850            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6851          } else {
6852            compileNode = beforeTemplateCompileNode;
6853            $compileNode.html(content);
6854          }
6855
6856          directives.unshift(derivedSyncDirective);
6857
6858          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6859              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6860              previousCompileContext);
6861          forEach($rootElement, function(node, i) {
6862            if (node == compileNode) {
6863              $rootElement[i] = $compileNode[0];
6864            }
6865          });
6866          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6867
6868          while(linkQueue.length) {
6869            var scope = linkQueue.shift(),
6870                beforeTemplateLinkNode = linkQueue.shift(),
6871                linkRootElement = linkQueue.shift(),
6872                boundTranscludeFn = linkQueue.shift(),
6873                linkNode = $compileNode[0];
6874
6875            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6876              var oldClasses = beforeTemplateLinkNode.className;
6877
6878              if (!(previousCompileContext.hasElementTranscludeDirective &&
6879                  origAsyncDirective.replace)) {
6880                // it was cloned therefore we have to clone as well.
6881                linkNode = jqLiteClone(compileNode);
6882              }
6883
6884              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6885
6886              // Copy in CSS classes from original node
6887              safeAddClass(jqLite(linkNode), oldClasses);
6888            }
6889            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6890              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6891            } else {
6892              childBoundTranscludeFn = boundTranscludeFn;
6893            }
6894            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6895              childBoundTranscludeFn);
6896          }
6897          linkQueue = null;
6898        }).
6899        error(function(response, code, headers, config) {
6900          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6901        });
6902
6903      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6904        var childBoundTranscludeFn = boundTranscludeFn;
6905        if (linkQueue) {
6906          linkQueue.push(scope);
6907          linkQueue.push(node);
6908          linkQueue.push(rootElement);
6909          linkQueue.push(childBoundTranscludeFn);
6910        } else {
6911          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6912            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6913          }
6914          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
6915        }
6916      };
6917    }
6918
6919
6920    /**
6921     * Sorting function for bound directives.
6922     */
6923    function byPriority(a, b) {
6924      var diff = b.priority - a.priority;
6925      if (diff !== 0) return diff;
6926      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6927      return a.index - b.index;
6928    }
6929
6930
6931    function assertNoDuplicate(what, previousDirective, directive, element) {
6932      if (previousDirective) {
6933        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6934            previousDirective.name, directive.name, what, startingTag(element));
6935      }
6936    }
6937
6938
6939      function addTextInterpolateDirective(directives, text) {
6940        var interpolateFn = $interpolate(text, true);
6941        if (interpolateFn) {
6942          directives.push({
6943            priority: 0,
6944            compile: function textInterpolateCompileFn(templateNode) {
6945              // when transcluding a template that has bindings in the root
6946              // then we don't have a parent and should do this in the linkFn
6947              var parent = templateNode.parent(), hasCompileParent = parent.length;
6948              if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
6949
6950              return function textInterpolateLinkFn(scope, node) {
6951                var parent = node.parent(),
6952                  bindings = parent.data('$binding') || [];
6953                bindings.push(interpolateFn);
6954                parent.data('$binding', bindings);
6955                if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
6956                scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6957                  node[0].nodeValue = value;
6958                });
6959              };
6960            }
6961          });
6962        }
6963      }
6964
6965
6966    function getTrustedContext(node, attrNormalizedName) {
6967      if (attrNormalizedName == "srcdoc") {
6968        return $sce.HTML;
6969      }
6970      var tag = nodeName_(node);
6971      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6972      if (attrNormalizedName == "xlinkHref" ||
6973          (tag == "FORM" && attrNormalizedName == "action") ||
6974          (tag != "IMG" && (attrNormalizedName == "src" ||
6975                            attrNormalizedName == "ngSrc"))) {
6976        return $sce.RESOURCE_URL;
6977      }
6978    }
6979
6980
6981    function addAttrInterpolateDirective(node, directives, value, name) {
6982      var interpolateFn = $interpolate(value, true);
6983
6984      // no interpolation found -> ignore
6985      if (!interpolateFn) return;
6986
6987
6988      if (name === "multiple" && nodeName_(node) === "SELECT") {
6989        throw $compileMinErr("selmulti",
6990            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6991            startingTag(node));
6992      }
6993
6994      directives.push({
6995        priority: 100,
6996        compile: function() {
6997            return {
6998              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6999                var $$observers = (attr.$$observers || (attr.$$observers = {}));
7000
7001                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
7002                  throw $compileMinErr('nodomevents',
7003                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
7004                          "ng- versions (such as ng-click instead of onclick) instead.");
7005                }
7006
7007                // we need to interpolate again, in case the attribute value has been updated
7008                // (e.g. by another directive's compile function)
7009                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
7010
7011                // if attribute was updated so that there is no interpolation going on we don't want to
7012                // register any observers
7013                if (!interpolateFn) return;
7014
7015                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
7016                // actual attr value
7017                attr[name] = interpolateFn(scope);
7018                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
7019                (attr.$$observers && attr.$$observers[name].$$scope || scope).
7020                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
7021                    //special case for class attribute addition + removal
7022                    //so that class changes can tap into the animation
7023                    //hooks provided by the $animate service. Be sure to
7024                    //skip animations when the first digest occurs (when
7025                    //both the new and the old values are the same) since
7026                    //the CSS classes are the non-interpolated values
7027                    if(name === 'class' && newValue != oldValue) {
7028                      attr.$updateClass(newValue, oldValue);
7029                    } else {
7030                      attr.$set(name, newValue);
7031                    }
7032                  });
7033              }
7034            };
7035          }
7036      });
7037    }
7038
7039
7040    /**
7041     * This is a special jqLite.replaceWith, which can replace items which
7042     * have no parents, provided that the containing jqLite collection is provided.
7043     *
7044     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
7045     *                               in the root of the tree.
7046     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
7047     *                                  the shell, but replace its DOM node reference.
7048     * @param {Node} newNode The new DOM node.
7049     */
7050    function replaceWith($rootElement, elementsToRemove, newNode) {
7051      var firstElementToRemove = elementsToRemove[0],
7052          removeCount = elementsToRemove.length,
7053          parent = firstElementToRemove.parentNode,
7054          i, ii;
7055
7056      if ($rootElement) {
7057        for(i = 0, ii = $rootElement.length; i < ii; i++) {
7058          if ($rootElement[i] == firstElementToRemove) {
7059            $rootElement[i++] = newNode;
7060            for (var j = i, j2 = j + removeCount - 1,
7061                     jj = $rootElement.length;
7062                 j < jj; j++, j2++) {
7063              if (j2 < jj) {
7064                $rootElement[j] = $rootElement[j2];
7065              } else {
7066                delete $rootElement[j];
7067              }
7068            }
7069            $rootElement.length -= removeCount - 1;
7070            break;
7071          }
7072        }
7073      }
7074
7075      if (parent) {
7076        parent.replaceChild(newNode, firstElementToRemove);
7077      }
7078      var fragment = document.createDocumentFragment();
7079      fragment.appendChild(firstElementToRemove);
7080      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
7081      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
7082        var element = elementsToRemove[k];
7083        jqLite(element).remove(); // must do this way to clean up expando
7084        fragment.appendChild(element);
7085        delete elementsToRemove[k];
7086      }
7087
7088      elementsToRemove[0] = newNode;
7089      elementsToRemove.length = 1;
7090    }
7091
7092
7093    function cloneAndAnnotateFn(fn, annotation) {
7094      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
7095    }
7096  }];
7097}
7098
7099var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
7100/**
7101 * Converts all accepted directives format into proper directive name.
7102 * All of these will become 'myDirective':
7103 *   my:Directive
7104 *   my-directive
7105 *   x-my-directive
7106 *   data-my:directive
7107 *
7108 * Also there is special case for Moz prefix starting with upper case letter.
7109 * @param name Name to normalize
7110 */
7111function directiveNormalize(name) {
7112  return camelCase(name.replace(PREFIX_REGEXP, ''));
7113}
7114
7115/**
7116 * @ngdoc type
7117 * @name $compile.directive.Attributes
7118 *
7119 * @description
7120 * A shared object between directive compile / linking functions which contains 
7120normalized DOM
7121 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
7122 * needed since all of these are treated as equivalent in Angular:
7123 *
7124 * ```
7125 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7126 * ```
7127 */
7128
7129/**
7130 * @ngdoc property
7131 * @name $compile.directive.Attributes#$attr
7132 * @returns {object} A map of DOM element attribute names to the normalized name. This is
7133 *                   needed to do reverse lookup from normalized name back to actual name.
7134 */
7135
7136
7137/**
7138 * @ngdoc method
7139 * @name $compile.directive.Attributes#$set
7140 * @kind function
7141 *
7142 * @description
7143 * Set DOM element attribute value.
7144 *
7145 *
7146 * @param {string} name Normalized element attribute name of the property to modify. The name is
7147 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7148 *          property to the original name.
7149 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7150 */
7151
7152
7153
7154/**
7155 * Closure compiler type information
7156 */
7157
7158function nodesetLinkingFn(
7159  /* angular.Scope */ scope,
7160  /* NodeList */ nodeList,
7161  /* Element */ rootElement,
7162  /* function(Function) */ boundTranscludeFn
7163){}
7164
7165function directiveLinkingFn(
7166  /* nodesetLinkingFn */ nodesetLinkingFn,
7167  /* angular.Scope */ scope,
7168  /* Node */ node,
7169  /* Element */ rootElement,
7170  /* function(Function) */ boundTranscludeFn
7171){}
7172
7173function tokenDifference(str1, str2) {
7174  var values = '',
7175      tokens1 = str1.split(/\s+/),
7176      tokens2 = str2.split(/\s+/);
7177
7178  outer:
7179  for(var i = 0; i < tokens1.length; i++) {
7180    var token = tokens1[i];
7181    for(var j = 0; j < tokens2.length; j++) {
7182      if(token == tokens2[j]) continue outer;
7183    }
7184    values += (values.length > 0 ? ' ' : '') + token;
7185  }
7186  return values;
7187}
7188
7189/**
7190 * @ngdoc provider
7191 * @name $controllerProvider
7192 * @description
7193 * The {@link ng.$controller $controller service} is used by Angular to create new
7194 * controllers.
7195 *
7196 * This provider allows controller registration via the
7197 * {@link ng.$controllerProvider#register register} method.
7198 */
7199function $ControllerProvider() {
7200  var controllers = {},
7201      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7202
7203
7204  /**
7205   * @ngdoc method
7206   * @name $controllerProvider#register
7207   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7208   *    the names and the values are the constructors.
7209   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7210   *    annotations in the array notation).
7211   */
7212  this.register = function(name, constructor) {
7213    assertNotHasOwnProperty(name, 'controller');
7214    if (isObject(name)) {
7215      extend(controllers, name);
7216    } else {
7217      controllers[name] = constructor;
7218    }
7219  };
7220
7221
7222  this.$get = ['$injector', '$window', function($injector, $window) {
7223
7224    /**
7225     * @ngdoc service
7226     * @name $controller
7227     * @requires $injector
7228     *
7229     * @param {Function|string} constructor If called with a function then it's considered to be the
7230     *    controller constructor function. Otherwise it's considered to be a string which is used
7231     *    to retrieve the controller constructor using the following steps:
7232     *
7233     *    * check if a controller with given name is registered via `$controllerProvider`
7234     *    * check if evaluating the string on the current scope returns a constructor
7235     *    * check `window[constructor]` on the global `window` object
7236     *
7237     * @param {Object} locals Injection locals for Controller.
7238     * @return {Object} Instance of given controller.
7239     *
7240     * @description
7241     * `$controller` service is responsible for instantiating controllers.
7242     *
7243     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7244     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7245     */
7246    return function(expression, locals) {
7247      var instance, match, constructor, identifier;
7248
7249      if(isString(expression)) {
7250        match = expression.match(CNTRL_REG),
7251        constructor = match[1],
7252        identifier = match[3];
7253        expression = controllers.hasOwnProperty(constructor)
7254            ? controllers[constructor]
7255            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7256
7257        assertArgFn(expression, constructor, true);
7258      }
7259
7260      instance = $injector.instantiate(expression, locals);
7261
7262      if (identifier) {
7263        if (!(locals && typeof locals.$scope === 'object')) {
7264          throw minErr('$controller')('noscp',
7265              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7266              constructor || expression.name, identifier);
7267        }
7268
7269        locals.$scope[identifier] = instance;
7270      }
7271
7272      return instance;
7273    };
7274  }];
7275}
7276
7277/**
7278 * @ngdoc service
7279 * @name $document
7280 * @requires $window
7281 *
7282 * @description
7283 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7284 *
7285 * @example
7286   <example module="documentExample">
7287     <file name="index.html">
7288       <div ng-controller="ExampleController">
7289         <p>$document title: <b ng-bind="title"></b></p>
7290         <p>window.document title: <b ng-bind="windowTitle"></b></p>
7291       </div>
7292     </file>
7293     <file name="script.js">
7294       angular.module('documentExample', [])
7295         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
7296           $scope.title = $document[0].title;
7297           $scope.windowTitle = angular.element(window.document)[0].title;
7298         }]);
7299     </file>
7300   </example>
7301 */
7302function $DocumentProvider(){
7303  this.$get = ['$window', function(window){
7304    return jqLite(window.document);
7305  }];
7306}
7307
7308/**
7309 * @ngdoc service
7310 * @name $exceptionHandler
7311 * @requires ng.$log
7312 *
7313 * @description
7314 * Any uncaught exception in angular expressions is delegated to this service.
7315 * The default implementation simply delegates to `$log.error` which logs it into
7316 * the browser console.
7317 *
7318 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7319 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7320 *
7321 * ## Example:
7322 *
7323 * ```js
7324 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7325 *     return function (exception, cause) {
7326 *       exception.message += ' (caused by "' + cause + '")';
7327 *       throw exception;
7328 *     };
7329 *   });
7330 * ```
7331 *
7332 * This example will override the normal action of `$exceptionHandler`, to make angular
7333 * exceptions fail hard when they happen, instead of just logging to the console.
7334 *
7335 * @param {Error} exception Exception associated with the error.
7336 * @param {string=} cause optional information about the context in which
7337 *       the error was thrown.
7338 *
7339 */
7340function $ExceptionHandlerProvider() {
7341  this.$get = ['$log', function($log) {
7342    return function(exception, cause) {
7343      $log.error.apply($log, arguments);
7344    };
7345  }];
7346}
7347
7348/**
7349 * Parse headers into key value object
7350 *
7351 * @param {string} headers Raw headers as a string
7352 * @returns {Object} Parsed headers as key value object
7353 */
7354function parseHeaders(headers) {
7355  var parsed = {}, key, val, i;
7356
7357  if (!headers) return parsed;
7358
7359  forEach(headers.split('\n'), function(line) {
7360    i = line.indexOf(':');
7361    key = lowercase(trim(line.substr(0, i)));
7362    val = trim(line.substr(i + 1));
7363
7364    if (key) {
7365      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
7366    }
7367  });
7368
7369  return parsed;
7370}
7371
7372
7373/**
7374 * Returns a function that provides access to parsed headers.
7375 *
7376 * Headers are lazy parsed when first requested.
7377 * @see parseHeaders
7378 *
7379 * @param {(string|Object)} headers Headers to provide access to.
7380 * @returns {function(string=)} Returns a getter function which if called with:
7381 *
7382 *   - if called with single an argument returns a single header value or null
7383 *   - if called with no arguments returns an object containing all headers.
7384 */
7385function headersGetter(headers) {
7386  var headersObj = isObject(headers) ? headers : undefined;
7387
7388  return function(name) {
7389    if (!headersObj) headersObj =  parseHeaders(headers);
7390
7391    if (name) {
7392      return headersObj[lowercase(name)] || null;
7393    }
7394
7395    return headersObj;
7396  };
7397}
7398
7399
7400/**
7401 * Chain all given functions
7402 *
7403 * This function is used for both request and response transforming
7404 *
7405 * @param {*} data Data to transform.
7406 * @param {function(string=)} headers Http headers getter fn.
7407 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7408 * @returns {*} Transformed data.
7409 */
7410function transformData(data, headers, fns) {
7411  if (isFunction(fns))
7412    return fns(data, headers);
7413
7414  forEach(fns, function(fn) {
7415    data = fn(data, headers);
7416  });
7417
7418  return data;
7419}
7420
7421
7422function isSuccess(status) {
7423  return 200 <= status && status < 300;
7424}
7425
7426
7427/**
7428 * @ngdoc provider
7429 * @name $httpProvider
7430 * @description
7431 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
7432 * */
7433function $HttpProvider() {
7434  var JSON_START = /^\s*(\[|\{[^\{])/,
7435      JSON_END = /[\}\]]\s*$/,
7436      PROTECTION_PREFIX = /^\)\]\}',?\n/,
7437      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7438
7439  /**
7440   * @ngdoc property
7441   * @name $httpProvider#defaults
7442   * @description
7443   *
7444   * Object containing default values for all {@link ng.$http $http} requests.
7445   *
7446   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
7447   * Defaults value is `'XSRF-TOKEN'`.
7448   *
7449   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
7450   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
7451   *
7452   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
7453   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
7454   * setting default headers.
7455   *     - **`defaults.headers.common`**
7456   *     - **`defaults.headers.post`**
7457   *     - **`defaults.headers.put`**
7458   *     - **`defaults.headers.patch`**
7459   **/
7460  var defaults = this.defaults = {
7461    // transform incoming response data
7462    transformResponse: [function(data) {
7463      if (isString(data)) {
7464        // strip json vulnerability protection prefix
7465        data = data.replace(PROTECTION_PREFIX, '');
7466        if (JSON_START.test(data) && JSON_END.test(data))
7467          data = fromJson(data);
7468      }
7469      return data;
7470    }],
7471
7472    // transform outgoing request data
7473    transformRequest: [function(d) {
7474      return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7475    }],
7476
7477    // default headers
7478    headers: {
7479      common: {
7480        'Accept': 'application/json, text/plain, */*'
7481      },
7482      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7483      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7484      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
7485    },
7486
7487    xsrfCookieName: 'XSRF-TOKEN',
7488    xsrfHeaderName: 'X-XSRF-TOKEN'
7489  };
7490
7491  /**
7492   * Are ordered by request, i.e. they are applied in the same order as the
7493   * array, on request, but reverse order, on response.
7494   */
7495  var interceptorFactories = this.interceptors = [];
7496
7497  /**
7498   * For historical reasons, response interceptors are ordered by the order in which
7499   * they are applied to the response. (This is the opposite of interceptorFactories)
7500   */
7501  var responseInterceptorFactories = this.responseInterceptors = [];
7502
7503  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7504      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7505
7506    var defaultCache = $cacheFactory('$http');
7507
7508    /**
7509     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7510     * The reversal is needed so that we can build up the interception chain around the
7511     * server request.
7512     */
7513    var reversedInterceptors = [];
7514
7515    forEach(interceptorFactories, function(interceptorFactory) {
7516      reversedInterceptors.unshift(isString(interceptorFactory)
7517          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7518    });
7519
7520    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7521      var responseFn = isString(interceptorFactory)
7522          ? $injector.get(interceptorFactory)
7523          : $injector.invoke(interceptorFactory);
7524
7525      /**
7526       * Response interceptors go before "around" interceptors (no real reason, just
7527       * had to pick one.) But they are already reversed, so we can't use unshift, hence
7528       * the splice.
7529       */
7530      reversedInterceptors.splice(index, 0, {
7531        response: function(response) {
7532          return responseFn($q.when(response));
7533        },
7534        responseError: function(response) {
7535          return responseFn($q.reject(response));
7536        }
7537      });
7538    });
7539
7540
7541    /**
7542     * @ngdoc service
7543     * @kind function
7544     * @name $http
7545     * @requires ng.$httpBackend
7546     * @requires $cacheFactory
7547     * @requires $rootScope
7548     * @requires $q
7549     * @requires $injector
7550     *
7551     * @description
7552     * The `$http` service is a core Angular service that facilitates communication with the remote
7553     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7554     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7555     *
7556     * For unit testing applications that use `$http` service, see
7557     * {@link ngMock.$httpBackend $httpBackend mock}.
7558     *
7559     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7560     * $resource} service.
7561     *
7562     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7563     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7564     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7565     *
7566     *
7567     * # General usage
7568     * The `$http` service is a function which takes a single argument — a configuration object —
7569     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7570     * with two $http specific methods: `success` and `error`.
7571     *
7572     * ```js
7573     *   $http({method: 'GET', url: '/someUrl'}).
7574     *     success(function(data, status, headers, config) {
7575     *       // this callback will be called asynchronously
7576     *       // when the response is available
7577     *     }).
7578     *     error(function(data, status, headers, config) {
7579     *       // called asynchronously if an error occurs
7580     *       // or server returns response with an error status.
7581     *     });
7582     * ```
7583     *
7584     * Since the returned value of calling the $http function is a `promise`, you can also use
7585     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7586     * an object representing the response. See the API signature and type info below for more
7587     * details.
7588     *
7589     * A response status code between 200 and 299 is considered a success status and
7590     * will result in the success callback being called. Note that if the response is a redirect,
7591     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7592     * called for such responses.
7593     *
7594     * # Writing Unit Tests that use $http
7595     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7596     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7597     * request using trained responses.
7598     *
7599     * ```
7600     * $httpBackend.expectGET(...);
7601     * $http.get(...);
7602     * $httpBackend.flush();
7603     * ```
7604     *
7605     * # Shortcut methods
7606     *
7607     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7608     * request data must be passed in for POST/PUT requests.
7609     *
7610     * ```js
7611     *   $http.get('/someUrl').success(successCallback);
7612     *   $http.post('/someUrl', data).success(successCallback);
7613     * ```
7614     *
7615     * Complete list of shortcut methods:
7616     *
7617     * - {@link ng.$http#get $http.get}
7618     * - {@link ng.$http#head $http.head}
7619     * - {@link ng.$http#post $http.post}
7620     * - {@link ng.$http#put $http.put}
7621     * - {@link ng.$http#delete $http.delete}
7622     * - {@link ng.$http#jsonp $http.jsonp}
7623     * - {@link ng.$http#patch $http.patch}
7624     *
7625     *
7626     * # Setting HTTP Headers
7627     *
7628     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7629     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7630     * object, which currently contains this default configuration:
7631     *
7632     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7633     *   - `Accept: application/json, text/plain, * / *`
7634     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7635     *   - `Content-Type: application/json`
7636     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7637     *   - `Content-Type: application/json`
7638     *
7639     * To add or overwrite these defaults, simply add or remove a property from these configuration
7640     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7641     * with the lowercased HTTP method name as the key, e.g.
7642     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7643     *
7644     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7645     * fashion. For example:
7646     *
7647     * ```
7648     * module.run(function($http) {
7649     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7650     * });
7651     * ```
7652     *
7653     * In addition, you can supply a `headers` property in the config object passed when
7654     * calling `$http(config)`, which overrides the defaults without changing them globally.
7655     *
7656     *
7657     * # Transforming Requests and Responses
7658     *
7659     * Both requests and responses can be transformed using transform functions. By default, Angular
7660     * applies these transformations:
7661     *
7662     * Request transformations:
7663     *
7664     * - If the `data` property of the request configuration object contains an object, serialize it
7665     *   into JSON format.
7666     *
7667     * Response transformations:
7668     *
7669     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7670     *  - If JSON response is detected, deserialize it using a JSON parser.
7671     *
7672     * To globally augment or override the default transforms, modify the
7673     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7674     * properties. These properties are by default an array of transform functions, which allows you
7675     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7676     * also decide to completely override any default transformations by assigning your
7677     * transformation functions to these properties directly without the array wrapper.  These defaults
7678     * are again available on the $http factory at run-time, which may be useful if you have run-time
7679     * services you wish to be involved in your transformations.
7680     *
7681     * Similarly, to locally override the request/response transforms, augment the
7682     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7683     * into `$http`.
7684     *
7685     *
7686     * # Caching
7687     *
7688     * To enable caching, set the request configuration `cache` property to `true` (to use default
7689     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7690     * When the cache is enabled, `$http` stores the response from the server in the specified
7691     * cache. The next time the same request is made, the response is served from the cache without
7692     * sending a request to the server.
7693     *
7694     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7695     * the same way that real requests are.
7696     *
7697     * If there are multiple GET requests for the same URL that should be cached using the same
7698     * cache, but the cache is not populated yet, only one request to the server will be made and
7699     * the remaining requests will be fulfilled using the response from the first request.
7700     *
7701     * You can change the default cache to a new object (built with
7702     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7703     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7704     * their `cache` property to `true` will now use this cache object.
7705     *
7706     * If you set the default cache to `false` then only requests that specify their own custom
7707     * cache object will be cached.
7708     *
7709     * # Interceptors
7710     *
7711     * Before you start creating interceptors, be sure to understand the
7712     * {@link ng.$q $q and deferred/promise APIs}.
7713     *
7714     * For purposes of global error handling, authentication, or any kind of synchronous or
7715     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7716     * able to intercept requests before they are handed to the server and
7717     * responses before they are handed over to the application code that
7718     * initiated these requests. The interceptors leverage the {@link ng.$q
7719     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7720     *
7721     * The interceptors are service factories that are registered with the `$httpProvider` by
7722     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7723     * injected with dependencies (if specified) and returns the interceptor.
7724     *
7725     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7726     *
7727     *   * `request`: interceptors get called with a http `config` object. The function is free to
7728     *     modify the `config` object or create a new one. The function needs to return the `config`
7729     *     object directly, or a promise containing the `config` or a new `config` object.
7730     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7731     *     resolved with a rejection.
7732     *   * `response`: interceptors get called with http `response` object. The function is free to
7733     *     modify the `response` object or create a new one. The function needs to return the `response`
7734     *     object directly, or as a promise containing the `response` or a new `response` object.
7735     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7736     *     resolved with a rejection.
7737     *
7738     *
7739     * ```js
7740     *   // register the interceptor as a service
7741     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7742     *     return {
7743     *       // optional method
7744     *       'request': function(config) {
7745     *         // do something on success
7746     *         return config;
7747     *       },
7748     *
7749     *       // optional method
7750     *      'requestError': function(rejection) {
7751     *         // do something on error
7752     *         if (canRecover(rejection)) {
7753     *           return responseOrNewPromise
7754     *         }
7755     *         return $q.reject(rejection);
7756     *       },
7757     *
7758     *
7759     *
7760     *       // optional method
7761     *       'response': function(response) {
7762     *         // do something on success
7763     *         return response;
7764     *       },
7765     *
7766     *       // optional method
7767     *      'responseError': function(rejection) {
7768     *         // do something on error
7769     *         if (canRecover(rejection)) {
7770     *           return responseOrNewPromise
7771     *         }
7772     *         return $q.reject(rejection);
7773     *       }
7774     *     };
7775     *   });
7776     *
7777     *   $httpProvider.interceptors.push('myHttpInterceptor');
7778     *
7779     *
7780     *   // alternatively, register the interceptor via an anonymous factory
7781     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7782     *     return {
7783     *      'request': function(config) {
7784     *          // same as above
7785     *       },
7786     *
7787     *       'response': function(response) {
7788     *          // same as above
7789     *       }
7790     *     };
7791     *   });
7792     * ```
7793     *
7794     * # Response interceptors (DEPRECATED)
7795     *
7796     * Before you start creating interceptors, be sure to understand the
7797     * {@link ng.$q $q and deferred/promise APIs}.
7798     *
7799     * For purposes of global error handling, authentication or any kind of synchronous or
7800     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7801     * responses for http requests before they are handed over to the application code that
7802     * initiated these requests. The response interceptors leverage the {@link ng.$q
7803     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7804     *
7805     * The interceptors are service factories that are registered with the $httpProvider by
7806     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7807     * injected with dependencies (if specified) and returns the interceptor  — a function that
7808     * takes a {@link ng.$q promise} and returns the original or a new promise.
7809     *
7810     * ```js
7811     *   // register the interceptor as a service
7812     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7813     *     return function(promise) {
7814     *       return promise.then(function(response) {
7815     *         // do something on success
7816     *         return response;
7817     *       }, function(response) {
7818     *         // do something on error
7819     *         if (canRecover(response)) {
7820     *           return responseOrNewPromise
7821     *         }
7822     *         return $q.reject(response);
7823     *       });
7824     *     }
7825     *   });
7826     *
7827     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7828     *
7829     *
7830     *   // register the interceptor via an anonymous factory
7831     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7832     *     return function(promise) {
7833     *       // same as above
7834     *     }
7835     *   });
7836     * ```
7837     *
7838     *
7839     * # Security Considerations
7840     *
7841     * When designing web applications, consider security threats from:
7842     *
7843     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7844     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7845     *
7846     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7847     * pre-configured with strategies that address these issues, but for this to work backend server
7848     * cooperation is required.
7849     *
7850     * ## JSON Vulnerability Protection
7851     *
7852     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7853     * allows third party website to turn your JSON resource URL into
7854     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7855     * counter this your server can prefix all JSON requests with following str
7855ing `")]}',\n"`.
7856     * Angular will automatically strip the prefix before processing it as JSON.
7857     *
7858     * For example if your server needs to return:
7859     * ```js
7860     * ['one','two']
7861     * ```
7862     *
7863     * which is vulnerable to attack, your server can return:
7864     * ```js
7865     * )]}',
7866     * ['one','two']
7867     * ```
7868     *
7869     * Angular will strip the prefix, before processing the JSON.
7870     *
7871     *
7872     * ## Cross Site Request Forgery (XSRF) Protection
7873     *
7874     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7875     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7876     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7877     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7878     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7879     * the XHR came from JavaScript running on your domain. The header will not be set for
7880     * cross-domain requests.
7881     *
7882     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7883     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7884     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7885     * that only JavaScript running on your domain could have sent the request. The token must be
7886     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7887     * making up its own tokens). We recommend that the token is a digest of your site's
7888     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
7889     * for added security.
7890     *
7891     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7892     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7893     * or the per-request config object.
7894     *
7895     *
7896     * @param {object} config Object describing the request to be made and how it should be
7897     *    processed. The object has following properties:
7898     *
7899     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7900     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7901     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7902     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7903     *      JSONified.
7904     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7905     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7906     *      HTTP headers to send to the server. If the return value of a function is null, the
7907     *      header will not be sent.
7908     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7909     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7910     *    - **transformRequest** –
7911     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7912     *      transform function or an array of such functions. The transform function takes the http
7913     *      request body and headers and returns its transformed (typically serialized) version.
7914     *    - **transformResponse** –
7915     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7916     *      transform function or an array of such functions. The transform function takes the http
7917     *      response body and headers and returns its transformed (typically deserialized) version.
7918     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7919     *      GET request, otherwise if a cache instance built with
7920     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7921     *      caching.
7922     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7923     *      that should abort the request when resolved.
7924     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
7925     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
7926     *      for more information.
7927     *    - **responseType** - `{string}` - see
7928     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
7929     *
7930     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7931     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7932     *   method takes two arguments a success and an error callback which will be called with a
7933     *   response object. The `success` and `error` methods take a single argument - a function that
7934     *   will be called when the request succeeds or fails respectively. The arguments passed into
7935     *   these functions are destructured representation of the response object passed into the
7936     *   `then` method. The response object has these properties:
7937     *
7938     *   - **data** – `{string|Object}` – The response body transformed with the transform
7939     *     functions.
7940     *   - **status** – `{number}` – HTTP status code of the response.
7941     *   - **headers** – `{function([headerName])}` – Header getter function.
7942     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7943     *   - **statusText** – `{string}` – HTTP status text of the response.
7944     *
7945     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7946     *   requests. This is primarily meant to be used for debugging purposes.
7947     *
7948     *
7949     * @example
7950<example module="httpExample">
7951<file name="index.html">
7952  <div ng-controller="FetchController">
7953    <select ng-model="method">
7954      <option>GET</option>
7955      <option>JSONP</option>
7956    </select>
7957    <input type="text" ng-model="url" size="80"/>
7958    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7959    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7960    <button id="samplejsonpbtn"
7961      ng-click="updateModel('JSONP',
7962                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7963      Sample JSONP
7964    </button>
7965    <button id="invalidjsonpbtn"
7966      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7967        Invalid JSONP
7968      </button>
7969    <pre>http status code: {{status}}</pre>
7970    <pre>http response data: {{data}}</pre>
7971  </div>
7972</file>
7973<file name="script.js">
7974  angular.module('httpExample', [])
7975    .controller('FetchController', ['$scope', '$http', '$templateCache',
7976      function($scope, $http, $templateCache) {
7977        $scope.method = 'GET';
7978        $scope.url = 'http-hello.html';
7979
7980        $scope.fetch = function() {
7981          $scope.code = null;
7982          $scope.response = null;
7983
7984          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7985            success(function(data, status) {
7986              $scope.status = status;
7987              $scope.data = data;
7988            }).
7989            error(function(data, status) {
7990              $scope.data = data || "Request failed";
7991              $scope.status = status;
7992          });
7993        };
7994
7995        $scope.updateModel = function(method, url) {
7996          $scope.method = method;
7997          $scope.url = url;
7998        };
7999      }]);
8000</file>
8001<file name="http-hello.html">
8002  Hello, $http!
8003</file>
8004<file name="protractor.js" type="protractor">
8005  var status = element(by.binding('status'));
8006  var data = element(by.binding('data'));
8007  var fetchBtn = element(by.id('fetchbtn'));
8008  var sampleGetBtn = element(by.id('samplegetbtn'));
8009  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
8010  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
8011
8012  it('should make an xhr GET request', function() {
8013    sampleGetBtn.click();
8014    fetchBtn.click();
8015    expect(status.getText()).toMatch('200');
8016    expect(data.getText()).toMatch(/Hello, \$http!/);
8017  });
8018
8019  it('should make a JSONP request to angularjs.org', function() {
8020    sampleJsonpBtn.click();
8021    fetchBtn.click();
8022    expect(status.getText()).toMatch('200');
8023    expect(data.getText()).toMatch(/Super Hero!/);
8024  });
8025
8026  it('should make JSONP request to invalid URL and invoke the error handler',
8027      function() {
8028    invalidJsonpBtn.click();
8029    fetchBtn.click();
8030    expect(status.getText()).toMatch('0');
8031    expect(data.getText()).toMatch('Request failed');
8032  });
8033</file>
8034</example>
8035     */
8036    function $http(requestConfig) {
8037      var config = {
8038        method: 'get',
8039        transformRequest: defaults.transformRequest,
8040        transformResponse: defaults.transformResponse
8041      };
8042      var headers = mergeHeaders(requestConfig);
8043
8044      extend(config, requestConfig);
8045      config.headers = headers;
8046      config.method = uppercase(config.method);
8047
8048      var serverRequest = function(config) {
8049        headers = config.headers;
8050        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
8051
8052        // strip content-type if data is undefined
8053        if (isUndefined(reqData)) {
8054          forEach(headers, function(value, header) {
8055            if (lowercase(header) === 'content-type') {
8056                delete headers[header];
8057            }
8058          });
8059        }
8060
8061        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
8062          config.withCredentials = defaults.withCredentials;
8063        }
8064
8065        // send request
8066        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
8067      };
8068
8069      var chain = [serverRequest, undefined];
8070      var promise = $q.when(config);
8071
8072      // apply interceptors
8073      forEach(reversedInterceptors, function(interceptor) {
8074        if (interceptor.request || interceptor.requestError) {
8075          chain.unshift(interceptor.request, interceptor.requestError);
8076        }
8077        if (interceptor.response || interceptor.responseError) {
8078          chain.push(interceptor.response, interceptor.responseError);
8079        }
8080      });
8081
8082      while(chain.length) {
8083        var thenFn = chain.shift();
8084        var rejectFn = chain.shift();
8085
8086        promise = promise.then(thenFn, rejectFn);
8087      }
8088
8089      promise.success = function(fn) {
8090        promise.then(function(response) {
8091          fn(response.data, response.status, response.headers, config);
8092        });
8093        return promise;
8094      };
8095
8096      promise.error = function(fn) {
8097        promise.then(null, function(response) {
8098          fn(response.data, response.status, response.headers, config);
8099        });
8100        return promise;
8101      };
8102
8103      return promise;
8104
8105      function transformResponse(response) {
8106        // make a copy since the response must be cacheable
8107        var resp = extend({}, response, {
8108          data: transformData(response.data, response.headers, config.transformResponse)
8109        });
8110        return (isSuccess(response.status))
8111          ? resp
8112          : $q.reject(resp);
8113      }
8114
8115      function mergeHeaders(config) {
8116        var defHeaders = defaults.headers,
8117            reqHeaders = extend({}, config.headers),
8118            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
8119
8120        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
8121
8122        // using for-in instead of forEach to avoid unecessary iteration after header has been found
8123        defaultHeadersIteration:
8124        for (defHeaderName in defHeaders) {
8125          lowercaseDefHeaderName = lowercase(defHeaderName);
8126
8127          for (reqHeaderName in reqHeaders) {
8128            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
8129              continue defaultHeadersIteration;
8130            }
8131          }
8132
8133          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
8134        }
8135
8136        // execute if header value is a function for merged headers
8137        execHeaders(reqHeaders);
8138        return reqHeaders;
8139
8140        function execHeaders(headers) {
8141          var headerContent;
8142
8143          forEach(headers, function(headerFn, header) {
8144            if (isFunction(headerFn)) {
8145              headerContent = headerFn();
8146              if (headerContent != null) {
8147                headers[header] = headerContent;
8148              } else {
8149                delete headers[header];
8150              }
8151            }
8152          });
8153        }
8154      }
8155    }
8156
8157    $http.pendingRequests = [];
8158
8159    /**
8160     * @ngdoc method
8161     * @name $http#get
8162     *
8163     * @description
8164     * Shortcut method to perform `GET` request.
8165     *
8166     * @param {string} url Relative or absolute URL specifying the destination of the request
8167     * @param {Object=} config Optional configuration object
8168     * @returns {HttpPromise} Future object
8169     */
8170
8171    /**
8172     * @ngdoc method
8173     * @name $http#delete
8174     *
8175     * @description
8176     * Shortcut method to perform `DELETE` request.
8177     *
8178     * @param {string} url Relative or absolute URL specifying the destination of the request
8179     * @param {Object=} config Optional configuration object
8180     * @returns {HttpPromise} Future object
8181     */
8182
8183    /**
8184     * @ngdoc method
8185     * @name $http#head
8186     *
8187     * @description
8188     * Shortcut method to perform `HEAD` request.
8189     *
8190     * @param {string} url Relative or absolute URL specifying the destination of the request
8191     * @param {Object=} config Optional configuration object
8192     * @returns {HttpPromise} Future object
8193     */
8194
8195    /**
8196     * @ngdoc method
8197     * @name $http#jsonp
8198     *
8199     * @description
8200     * Shortcut method to perform `JSONP` request.
8201     *
8202     * @param {string} url Relative or absolute URL specifying the destination of the request.
8203     *                     The name of the callback should be the string `JSON_CALLBACK`.
8204     * @param {Object=} config Optional configuration object
8205     * @returns {HttpPromise} Future object
8206     */
8207    createShortMethods('get', 'delete', 'head', 'jsonp');
8208
8209    /**
8210     * @ngdoc method
8211     * @name $http#post
8212     *
8213     * @description
8214     * Shortcut method to perform `POST` request.
8215     *
8216     * @param {string} url Relative or absolute URL specifying the destination of the request
8217     * @param {*} data Request content
8218     * @param {Object=} config Optional configuration object
8219     * @returns {HttpPromise} Future object
8220     */
8221
8222    /**
8223     * @ngdoc method
8224     * @name $http#put
8225     *
8226     * @description
8227     * Shortcut method to perform `PUT` request.
8228     *
8229     * @param {string} url Relative or absolute URL specifying the destination of the request
8230     * @param {*} data Request content
8231     * @param {Object=} config Optional configuration object
8232     * @returns {HttpPromise} Future object
8233     */
8234    createShortMethodsWithData('post', 'put');
8235
8236        /**
8237         * @ngdoc property
8238         * @name $http#defaults
8239         *
8240         * @description
8241         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8242         * default headers, withCredentials as well as request and response transformations.
8243         *
8244         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8245         */
8246    $http.defaults = defaults;
8247
8248
8249    return $http;
8250
8251
8252    function createShortMethods(names) {
8253      forEach(arguments, function(name) {
8254        $http[name] = function(url, config) {
8255          return $http(extend(config || {}, {
8256            method: name,
8257            url: url
8258          }));
8259        };
8260      });
8261    }
8262
8263
8264    function createShortMethodsWithData(name) {
8265      forEach(arguments, function(name) {
8266        $http[name] = function(url, data, config) {
8267          return $http(extend(config || {}, {
8268            method: name,
8269            url: url,
8270            data: data
8271          }));
8272        };
8273      });
8274    }
8275
8276
8277    /**
8278     * Makes the request.
8279     *
8280     * !!! ACCESSES CLOSURE VARS:
8281     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8282     */
8283    function sendReq(config, reqData, reqHeaders) {
8284      var deferred = $q.defer(),
8285          promise = deferred.promise,
8286          cache,
8287          cachedResp,
8288          url = buildUrl(config.url, config.params);
8289
8290      $http.pendingRequests.push(config);
8291      promise.then(removePendingReq, removePendingReq);
8292
8293
8294      if ((config.cache || defaults.cache) && config.cache !== false &&
8295          (config.method === 'GET' || config.method === 'JSONP')) {
8296        cache = isObject(config.cache) ? config.cache
8297              : isObject(defaults.cache) ? defaults.cache
8298              : defaultCache;
8299      }
8300
8301      if (cache) {
8302        cachedResp = cache.get(url);
8303        if (isDefined(cachedResp)) {
8304          if (isPromiseLike(cachedResp)) {
8305            // cached request has already been sent, but there is no response yet
8306            cachedResp.then(removePendingReq, removePendingReq);
8307            return cachedResp;
8308          } else {
8309            // serving from cache
8310            if (isArray(cachedResp)) {
8311              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
8312            } else {
8313              resolvePromise(cachedResp, 200, {}, 'OK');
8314            }
8315          }
8316        } else {
8317          // put the promise for the non-transformed response into cache as a placeholder
8318          cache.put(url, promise);
8319        }
8320      }
8321
8322
8323      // if we won't have the response in cache, set the xsrf headers and
8324      // send the request to the backend
8325      if (isUndefined(cachedResp)) {
8326        var xsrfValue = urlIsSameOrigin(config.url)
8327            ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
8328            : undefined;
8329        if (xsrfValue) {
8330          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
8331        }
8332
8333        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8334            config.withCredentials, config.responseType);
8335      }
8336
8337      return promise;
8338
8339
8340      /**
8341       * Callback registered to $httpBackend():
8342       *  - caches the response if desired
8343       *  - resolves the raw $http promise
8344       *  - calls $apply
8345       */
8346      function done(status, response, headersString, statusText) {
8347        if (cache) {
8348          if (isSuccess(status)) {
8349            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8350          } else {
8351            // remove promise from the cache
8352            cache.remove(url);
8353          }
8354        }
8355
8356        resolvePromise(response, status, headersString, statusText);
8357        if (!$rootScope.$$phase) $rootScope.$apply();
8358      }
8359
8360
8361      /**
8362       * Resolves the raw $http promise.
8363       */
8364      function resolvePromise(response, status, headers, statusText) {
8365        // normalize internal statuses to 0
8366        status = Math.max(status, 0);
8367
8368        (isSuccess(status) ? deferred.resolve : deferred.reject)({
8369          data: response,
8370          status: status,
8371          headers: headersGetter(headers),
8372          config: config,
8373          statusText : statusText
8374        });
8375      }
8376
8377
8378      function removePendingReq() {
8379        var idx = indexOf($http.pendingRequests, config);
8380        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8381      }
8382    }
8383
8384
8385    function buildUrl(url, params) {
8386      if (!params) return url;
8387      var parts = [];
8388      forEachSorted(params, function(value, key) {
8389        if (value === null || isUndefined(value)) return;
8390        if (!isArray(value)) value = [value];
8391
8392        forEach(value, function(v) {
8393          if (isObject(v)) {
8394            if (isDate(v)){
8395              v = v.toISOString();
8396            } else if (isObject(v)) {
8397              v = toJson(v);
8398            }
8399          }
8400          parts.push(encodeUriQuery(key) + '=' +
8401                     encodeUriQuery(v));
8402        });
8403      });
8404      if(parts.length > 0) {
8405        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8406      }
8407      return url;
8408    }
8409  }];
8410}
8411
8412function createXhr(method) {
8413    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8414    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8415    //if it is available
8416    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
8417      !window.XMLHttpRequest)) {
8418      return new window.ActiveXObject("Microsoft.XMLHTTP");
8419    } else if (window.XMLHttpRequest) {
8420      return new window.XMLHttpRequest();
8421    }
8422
8423    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8424}
8425
8426/**
8427 * @ngdoc service
8428 * @name $httpBackend
8429 * @requires $window
8430 * @requires $document
8431 *
8432 * @description
8433 * HTTP backend used by the {@link ng.$http service} that delegates to
8434 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8435 *
8436 * You should never need to use this service directly, instead use the higher-level abstractions:
8437 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8438 *
8439 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8440 * $httpBackend} which can be trained with responses.
8441 */
8442function $HttpBackendProvider() {
8443  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
8444    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8445  }];
8446}
8447
8448function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8449  var ABORTED = -1;
8450
8451  // TODO(vojta): fix the signature
8452  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8453    var status;
8454    $browser.$$incOutstandingRequestCount();
8455    url = url || $browser.url();
8456
8457    if (lowercase(method) == 'jsonp') {
8458      var callbackId = '_' + (callbacks.counter++).toString(36);
8459      callbacks[callbackId] = function(data) {
8460        callbacks[callbackId].data = data;
8461        callbacks[callbackId].called = true;
8462      };
8463
8464      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8465          callbackId, function(status, text) {
8466        completeRequest(callback, status, callbacks[callbackId].data, "", text);
8467        callbacks[callbackId] = noop;
8468      });
8469    } else {
8470
8471      var xhr = createXhr(method);
8472
8473      xhr.open(method, url, true);
8474      forEach(headers, function(value, key) {
8475        if (isDefined(value)) {
8476            xhr.setRequestHeader(key, value);
8477        }
8478      });
8479
8480      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8481      // response is in the cache. the promise api will ensure that to the app code the api is
8482      // always async
8483      xhr.onreadystatechange = function() {
8484        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8485        // xhrs that are resolved while the app is in the background (see #5426).
8486        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8487        // continuing
8488        //
8489        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8490        // Safari respectively.
8491        if (xhr && xhr.readyState == 4) {
8492          var responseHeaders = null,
8493              response = null,
8494              statusText = '';
8495
8496          if(status !== ABORTED) {
8497            responseHeaders = xhr.getAllResponseHeaders();
8498
8499            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
8500            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8501            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8502          }
8503
8504          // Accessing statusText on an aborted xhr object will
8505          // throw an 'c00c023f error' in IE9 and lower, don't touch it.
8506          if (!(status === ABORTED && msie < 10)) {
8507            statusText = xhr.statusText;
8508          }
8509
8510          completeRequest(callback,
8511              status || xhr.status,
8512              response,
8513              responseHeaders,
8514              statusText);
8515        }
8516      };
8517
8518      if (withCredentials) {
8519        xhr.withCredentials = true;
8520      }
8521
8522      if (responseType) {
8523        try {
8524          xhr.responseType = responseType;
8525        } catch (e) {
8526          // WebKit added support for the json responseType value on 09/03/2013
8527          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8528          // known to throw when setting the value "json" as the response type. Other older
8529          // browsers implementing the responseType
8530          //
8531          // The json response type can be ignored if not supported, because JSON payloads are
8532          // parsed on the client-side regardless.
8533          if (responseType !== 'json') {
8534            throw e;
8535          }
8536        }
8537      }
8538
8539      xhr.send(post || null);
8540    }
8541
8542    if (timeout > 0) {
8543      var timeoutId = $browserDefer(timeoutRequest, timeout);
8544    } else if (isPromiseLike(timeout)) {
8545      timeout.then(timeoutRequest);
8546    }
8547
8548
8549    function timeoutRequest() {
8550      status = ABORTED;
8551      jsonpDone && jsonpDone();
8552      xhr && xhr.abort();
8553    }
8554
8555    function completeRequest(callback, status, response, headersString, statusText) {
8556      // cancel timeout and subsequent timeout promise resolution
8557      timeoutId && $browserDefer.cancel(timeoutId);
8558      jsonpDone = xhr = null;
8559
8560      // fix status code when it is 0 (0 status is undocumented).
8561      // Occurs when accessing file resources or on Android 4.1 stock browser
8562      // while retrieving files from application cache.
8563      if (status === 0) {
8564        status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8565      }
8566
8567      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8568      status = status === 1223 ? 204 : status;
8569      statusText = statusText || '';
8570
8571      callback(status, response, headersString, statusText);
8572      $browser.$$completeOutstandingRequest(noop);
8573    }
8574  };
8575
8576  function jsonpReq(url, callbackId, done) {
8577    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8578    // - fetches local scripts via XHR and evals them
8579    // - adds and immediately removes script elements from the document
8580    var script = rawDocument.createElement('script'), callback = null;
8581    script.type = "text/javascript";
8582    script.src = url;
8583    script.async = true;
8584
8585    callback = function(event) {
8586      removeEventListenerFn(script, "load", callback);
8587      removeEventListenerFn(script, "error", callback);
8588      rawDocument.body.removeChild(script);
8589      script = null;
8590      var status = -1;
8591      var text = "unknown";
8592
8593      if (event) {
8594        if (event.type === "load" && !callbacks[callbackId].called) {
8595          event = { type: "error" };
8596        }
8597        text = event.type;
8598        status = event.type === "error" ? 404 : 200;
8599      }
8600
8601      if (done) {
8602        done(status, text);
8603      }
8604    };
8605
8606    addEventListenerFn(script, "load", callback);
8607    addEventListenerFn(script, "error", callback);
8608
8609    if (msie <= 8) {
8610      script.onreadystatechange = function() {
8611        if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
8612          script.onreadystatechange = null;
8613          callback({
8614            type: 'load'
8615          });
8616        }
8617      };
8618    }
8619
8620    rawDocument.body.appendChild(script);
8621    return callback;
8622  }
8623}
8624
8625var $interpolateMinErr = minErr('$interpolate');
8626
8627/**
8628 * @ngdoc provider
8629 * @name $interpolateProvider
8630 * @kind function
8631 *
8632 * @description
8633 *
8634 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8635 *
8636 * @example
8637<example module="customInterpolationApp">
8638<file name="index.html">
8639<script>
8640  var customInterpolationApp = angular.module('customInterpolationApp', []);
8641
8642  customInterpolationApp.config(function($interpolateProvider) {
8643    $interpolateProvider.startSymbol('//');
8644    $interpolateProvider.endSymbol('//');
8645  });
8646
8647
8648  customInterpolationApp.controller('DemoController', function() {
8649      this.label = "This binding is brought you by // interpolation symbols.";
8650  });
8651</script>
8652<div ng-app="App" ng-controller="DemoController as demo">
8653    //demo.label//
8654</div>
8655</file>
8656<file name="protractor.js" type="protractor">
8657  it('should interpolate binding with custom symbols', function() {
8658    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8659  });
8660</file>
8661</example>
8662 */
8663function $InterpolateProvider() {
8664  var startSymbol = '{{';
8665  var endSymbol = '}}';
8666
8667  /**
8668   * @ngdoc method
8669   * @name $interpolateProvider#startSymbol
8670   * @description
8671   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8672   *
8673   * @param {string=} value new value to set the starting symbol to.
8674   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8675   */
8676  this.startSymbol = function(value){
8677    if (value) {
8678      startSymbol = value;
8679      return this;
8680    } else {
8681      return startSymbol;
8682    }
8683  };
8684
8685  /**
8686   * @ngdoc method
8687   * @name $interpolateProvider#endSymbol
8688   * @description
8689   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8690   *
8691   * @param {string=} value new value to set the ending symbol to.
8692   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8693   */
8694  this.endSymbol = function(value){
8695    if (value) {
8696      endSymbol = value;
8697      return this;
8698    } else {
8699      return endSymbol;
8700    }
8701  };
8702
8703
8704  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8705    var startSymbolLength = startSymbol.length,
8706        endSymbolLength = endSymbol.length;
8707
8708    /**
8709     * @ngdoc service
8710     * @name $interpolate
8711     * @kind function
8712     *
8713     * @requires $parse
8714     * @requires $sce
8715     *
8716     * @description
8717     *
8718     * Compiles a string with markup into an interpolation function. This service is used by the
8719     * HTML {@link ng.$compile $compile} service for data binding. See
8720     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8721     * interpolation markup.
8722     *
8723     *
8724     * ```js
8725     *   var $interpolate = ...; // injected
8726     *   var exp = $interpolate('Hello {{name | uppercase}}!');
8727     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8728     * ```
8729     *
8730     *
8731     * @param {string} text The text with markup to interpolate.
8732     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8733     *    embedded expression in order to return an interpolation function. Strings with no
8734     *    embedded expression will return null for the interpolation function.
8735     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8736     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8737     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8738     *    provides Strict Contextual Escaping for details.
8739     * @returns {function(context)} an interpolation function which is used to compute the
8740     *    interpolated string. The function has these parameters:
8741     *
8742     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8743     *      against.
8744     *
8745     */
8746    function $interpolate(text, mustHaveExpression, trustedContext) {
8747      var startIndex,
8748          endIndex,
8749          index = 0,
8750          parts = [],
8751          length = text.length,
8752          hasInterpolation = false,
8753          fn,
8754          exp,
8755          concat = [];
8756
8757      while(index < length) {
8758        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8759             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8760          (index != startIndex) && parts.push(text.substring(index, startIndex));
8761          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8762          fn.exp = exp;
8763          index = endIndex + endSymbolLength;
8764          hasInterpolation = true;
8765        } else {
8766          // we did not find anything, so we have to add the remainder to the parts array
8767          (index != length) && parts.push(text.substring(index));
8768          index = length;
8769        }
8770      }
8771
8772      if (!(length = parts.length)) {
8773        // we added, nothing, must have been an empty string.
8774        parts.push('');
8775        length = 1;
8776      }
8777
8778      // Concatenating expressions makes it hard to reason about whether some combination of
8779      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8780      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8781      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8782      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8783      // the load when auditing for XSS issues.
8784      if (trustedContext && parts.length > 1) {
8785          throw $interpolateMinErr('noconcat',
8786              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8787              "interpolations that concatenate multiple expressions when a trusted value is " +
8788              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8789      }
8790
8791      if (!mustHaveExpression  || hasInterpolation) {
8792        concat.length = length;
8793        fn = function(context) {
8794          try {
8795            for(var i = 0, ii = length, part; i<ii; i++) {
8796              if (typeof (part = parts[i]) == 'function') {
8797                part = part(context);
8798                if (trustedContext) {
8799                  part = $sce.getTrusted(trustedContext, part);
8800                } else {
8801                  part = $sce.valueOf(part);
8802                }
8803                if (part == null) { // null || undefined
8804                  part = '';
8805                } else {
8806                  switch (typeof part) {
8807                    case 'string':
8808                    {
8809                      break;
8810                    }
8811                    case 'number':
8812                    {
8813                      part = '' + part;
8814                      break;
8815                    }
8816                    default:
8817                    {
8818                      part = toJson(part);
8819                    }
8820                  }
8821                }
8822              }
8823              concat[i] = part;
8824            }
8825            return concat.join('');
8826          }
8827          catch(err) {
8828            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8829                err.toString());
8830            $exceptionHandler(newErr);
8831          }
8832        };
8833        fn.exp = text;
8834        fn.parts = parts;
8835        return fn;
8836      }
8837    }
8838
8839
8840    /**
8841     * @ngdoc method
8842     * @name $interpolate#startSymbol
8843     * @description
8844     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8845     *
8846     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8847     * the symbol.
8848     *
8849     * @returns {string} start symbol.
8850     */
8851    $interpolate.startSymbol = function() {
8852      return startSymbol;
8853    };
8854
8855
8856    /**
8857     * @ngdoc method
8858     * @name $interpolate#endSymbol
8859     * @description
8860     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8861     *
8862     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8863     * the symbol.
8864     *
8865     * @returns {string} end symbol.
8866     */
8867    $interpolate.endSymbol = function() {
8868      return endSymbol;
8869    };
8870
8871    return $interpolate;
8872  }];
8873}
8874
8875function $IntervalProvider() {
8876  this.$get = ['$rootScope', '$window', '$q',
8877       function($rootScope,   $window,   $q) {
8878    var intervals = {};
8879
8880
8881     /**
8882      * @ngdoc service
8883      * @name $interval
8884      *
8885      * @description
8886      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8887      * milliseconds.
8888      *
8889      * The return value of registering an interval function is a promise. This promise will be
8890      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8891      * run indefinitely if `count` is not defined. The value of the notification will be the
8892      * number of iterations that have run.
8893      * To cancel an interval, call `$interval.cancel(promise)`.
8894      *
8895      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
8896      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8897      * time.
8898      *
8899      * <div class="alert alert-warning">
8900      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8901      * with them.  In particular they are not automatically destroyed when a controller's scope or a
8902      * directive's element are destroyed.
8903      * You should take this into consideration and make sure to always cancel the interval at the
8904      * appropriate moment.  See the example below for more details on how and when to do this.
8905      * </div>
8906      *
8907      * @param {function()} fn A function that should be called repeatedly.
8908      * @param {number} delay Number of milliseconds between each function call.
8909      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8910      *   indefinitely.
8911      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8912      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
8913      * @returns {promise} A promise which will be notified on each iteration.
8914      *
8915      * @example
8916      * <example module="intervalExample">
8917      * <file name="index.html">
8918      *   <script>
8919      *     angular.module('intervalExample', [])
8920      *       .controller('ExampleController', ['$scope', '$interval',
8921      *         function($scope, $interval) {
8922      *           $scope.format = 'M/d/yy h:mm:ss a';
8923      *           $scope.blood_1 = 100;
8924      *           $scope.blood_2 = 120;
8925      *
8926      *           var stop;
8927      *           $scope.fight = function() {
8928      *             // Don't start a new fight if we are already fighting
8929      *             if ( angular.isDefined(stop) ) return;
8930      *
8931      *           stop = $interval(function() {
8932      *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8933      *               $scope.blood_1 = $scope.blood_1 - 3;
8934      *               $scope.blood_2 = $scope.blood_2 - 4;
8935      *             } else {
8936      *               $scope.stopFight();
8937      *             }
8938      *           }, 100);
8939      *         };
8940      *
8941      *         $scope.stopFight = function() {
8942      *           if (angular.isDefined(stop)) {
8943      *             $interval.cancel(stop);
8944      *             stop = undefined;
8945      *           }
8946      *         };
8947      *
8948      *         $scope.resetFight = function() {
8949      *           $scope.blood_1 = 100;
8950      *           $scope.blood_2 = 120;
8951      *         };
8952      *
8953      *         $scope.$on('$destroy', function() {
8954      *           // Make sure that the interval nis destroyed too
8955      *           $scope.stopFight();
8956      *         });
8957      *       }])
8958      *       // Register the 'myCurrentTime' directive factory method.
8959      *       // We inject $interval and dateFilter service since the factory method is DI.
8960      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
8961      *         function($interval, dateFilter) {
8962      *           // return the directive link function. (compile function not needed)
8963      *           return function(scope, element, attrs) {
8964      *             var format,  // date format
8965      *                 stopTime; // so that we can cancel the time updates
8966      *
8967      *             // used to update the UI
8968      *             function updateTime() {
8969      *               element.text(dateFilter(new Date(), format));
8970      *             }
8971      *
8972      *             // watch the expression, and update the UI on change.
8973      *             scope.$watch(attrs.myCurrentTime, function(value) {
8974      *               format = value;
8975      *               updateTime();
8976      *             });
8977      *
8978      *             stopTime = $interval(updateTime, 1000);
8979      *
8980      *             // listen on DOM destroy (removal) event, and cancel the next UI update
8981      *             // to prevent updating time after the DOM element was removed.
8982      *             element.bind('$destroy', function() {
8983      *               $interval.cancel(stopTime);
8984      *             });
8985      *           }
8986      *         }]);
8987      *   </script>
8988      *
8989      *   <div>
8990      *     <div ng-controller="ExampleController">
8991      *       Date format: <input ng-model="format"> <hr/>
8992      *       Current time is: <span my-current-time="format"></span>
8993      *       <hr/>
8994      *       Blood 1 : <font color='red'>{{blood_1}}</font>
8995      *       Blood 2 : <font color='red'>{{blood_2}}</font>
8996      *       <button type="button" data-ng-click="fight()">Fight</button>
8997      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
8998      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
8999      *     </div>
9000      *   </div>
9001      *
9002      * </file>
9003      * </example>
9004      */
9005    function interval(fn, delay, count, invokeApply) {
9006      var setInterval = $window.setInterval,
9007          clearInterval = $window.clearInterval,
9008          deferred = $q.defer(),
9009          promise = deferred.promise,
9010          iteration = 0,
9011          skipApply = (isDefined(invokeApply) && !invokeApply);
9012
9013      count = isDefined(count) ? count : 0;
9014
9015      promise.then(null, null, fn);
9016
9017      promise.$$intervalId = setInterval(function tick() {
9018        deferred.notify(iteration++);
9019
9020        if (count > 0 && iteration >= count) {
9021          deferred.resolve(iteration);
9022          clearInterval(promise.$$intervalId);
9023          delete intervals[promise.$$intervalId];
9024        }
9025
9026        if (!skipApply) $rootScope.$apply();
9027
9028      }, delay);
9029
9030      intervals[promise.$$intervalId] = deferred;
9031
9032      return promise;
9033    }
9034
9035
9036     /**
9037      * @ngdoc method
9038      * @name $interval#cancel
9039      *
9040      * @description
9041      * Cancels a task associated with the `promise`.
9042      *
9043      * @param {promise} promise returned by the `$interval` function.
9044      * @returns {boolean} Returns `true` if the task was successfully canceled.
9045      */
9046    interval.cancel = function(promise) {
9047      if (promise && promise.$$intervalId in intervals) {
9048        intervals[promise.$$intervalId].reject('canceled');
9049        $window.clearInterval(promise.$$intervalId);
9050        delete intervals[promise.$$intervalId];
9051        return true;
9052      }
9053      return false;
9054    };
9055
9056    return interval;
9057  }];
9058}
9059
9060/**
9061 * @ngdoc service
9062 * @name $locale
9063 *
9064 * @description
9065 * $locale service provides localization rules for various Angular components. As of right now the
9066 * only public api is:
9067 *
9068 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
9069 */
9070function $LocaleProvider(){
9071  this.$get = function() {
9072    return {
9073      id: 'en-us',
9074
9075      NUMBER_FORMATS: {
9076        DECIMAL_SEP: '.',
9077        GROUP_SEP: ',',
9078        PATTERNS: [
9079          { // Decimal Pattern
9080            minInt: 1,
9081            minFrac: 0,
9082            maxFrac: 3,
9083            posPre: '',
9084            posSuf: '',
9085            negPre: '-',
9086            negSuf: '',
9087            gSize: 3,
9088            lgSize: 3
9089          },{ //Currency Pattern
9090            minInt: 1,
9091            minFrac: 2,
9092            maxFrac: 2,
9093            posPre: '\u00A4',
9094            posSuf: '',
9095            negPre: '(\u00A4',
9096            negSuf: ')',
9097            gSize: 3,
9098            lgSize: 3
9099          }
9100        ],
9101        CURRENCY_SYM: '$'
9102      },
9103
9104      DATETIME_FORMATS: {
9105        MONTH:
9106            'January,February,March,April,May,June,July,August,September,October,November,December'
9107            .split(','),
9108        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
9109        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
9110        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
9111        AMPMS: ['AM','PM'],
9112        medium: 'MMM d, y h:mm:ss a',
9113        short: 'M/d/yy h:mm a',
9114        fullDate: 'EEEE, MMMM d, y',
9115        longDate: 'MMMM d, y',
9116        mediumDate: 'MMM d, y',
9117        shortDate: 'M/d/yy',
9118        mediumTime: 'h:mm:ss a',
9119        shortTime: 'h:mm a'
9120      },
9121
9122      pluralCat: function(num) {
9123        if (num === 1) {
9124          return 'one';
9125        }
9126        return 'other';
9127      }
9128    };
9129  };
9130}
9131
9132var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
9133    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
9134var $locationMinErr = minErr('$location');
9135
9136
9137/**
9138 * Encode path using encodeUriSegment, ignoring forward slashes
9139 *
9140 * @param {string} path Path to encode
9141 * @returns {string}
9142 */
9143function encodePath(path) {
9144  var segments = path.split('/'),
9145      i = segments.length;
9146
9147  while (i--) {
9148    segments[i] = encodeUriSegment(segments[i]);
9149  }
9150
9151  return segments.join('/');
9152}
9153
9154function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
9155  var parsedUrl = urlResolve(absoluteUrl, appBase);
9156
9157  locationObj.$$protocol = parsedUrl.protocol;
9158  locationObj.$$host = parsedUrl.hostname;
9159  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
9160}
9161
9162
9163function parseAppUrl(relativeUrl, locationObj, appBase) {
9164  var prefixed = (relativeUrl.charAt(0) !== '/');
9165  if (prefixed) {
9166    relativeUrl = '/' + relativeUrl;
9167  }
9168  var match = urlResolve(relativeUrl, appBase);
9169  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
9170      match.pathname.substring(1) : match.pathname);
9171  locationObj.$$search = parseKeyValue(match.search);
9172  locationObj.$$hash = decodeURIComponent(match.hash);
9173
9174  // make sure path starts with '/';
9175  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
9176    locationObj.$$path = '/' + locationObj.$$path;
9177  }
9178}
9179
9180
9181/**
9182 *
9183 * @param {string} begin
9184 * @param {string} whole
9185 * @returns {string} returns text from whole after begin or undefined if it does not begin with
9186 *                   expected string.
9187 */
9188function beginsWith(begin, whole) {
9189  if (whole.indexOf(begin) === 0) {
9190    return whole.substr(begin.length);
9191  }
9192}
9193
9194
9195function stripHash(url) {
9196  var index = url.indexOf('#');
9197  return index == -1 ? url : url.substr(0, index);
9198}
9199
9200
9201function stripFile(url) {
9202  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9203}
9204
9205/* return the server only (scheme://host:port) */
9206function serverBase(url) {
9207  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9208}
9209
9210
9211/**
9212 * LocationHtml5Url represents an url
9213 * This object is exposed as $location service when HTML5 mode is enabled and supported
9214 *
9215 * @constructor
9216 * @param {string} appBase application base URL
9217 * @param {string} basePrefix url path prefix
9218 */
9219function LocationHtml5Url(appBase, basePrefix) {
9220  this.$$html5 = true;
9221  basePrefix = basePrefix || '';
9222  var appBaseNoFile = stripFile(appBase);
9223  parseAbsoluteUrl(appBase, this, appBase);
9224
9225
9226  /**
9227   * Parse given html5 (regular) url string into properties
9228   * @param {string} newAbsoluteUrl HTML5 url
9229   * @private
9230   */
9231  this.$$parse = function(url) {
9232    var pathUrl = beginsWith(appBaseNoFile, url);
9233    if (!isString(pathUrl)) {
9234      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9235          appBaseNoFile);
9236    }
9237
9238    parseAppUrl(pathUrl, this, appBase);
9239
9240    if (!this.$$path) {
9241      this.$$path = '/';
9242    }
9243
9244    this.$$compose();
9245  };
9246
9247  /**
9248   * Compose url and update `absUrl` property
9249   * @private
9250   */
9251  this.$$compose = function() {
9252    var search = toKeyValue(this.$$search),
9253        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9254
9255    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9256    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9257  };
9258
9259  this.$$rewrite = function(url) {
9260    var appUrl, prevAppUrl;
9261
9262    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
9263      prevAppUrl = appUrl;
9264      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
9265        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9266      } else {
9267        return appBase + prevAppUrl;
9268      }
9269    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
9270      return appBaseNoFile + appUrl;
9271    } else if (appBaseNoFile == url + '/') {
9272      return appBaseNoFile;
9273    }
9274  };
9275}
9276
9277
9278/**
9279 * LocationHashbangUrl represents url
9280 * This object is exposed as $location service when developer doesn't opt into html5 mode.
9281 * It also serves as the base class for html5 mode fallback on legacy browsers.
9282 *
9283 * @constructor
9284 * @param {string} appBase application base URL
9285 * @param {string} hashPrefix hashbang prefix
9286 */
9287function LocationHashbangUrl(appBase, hashPrefix) {
9288  var appBaseNoFile = stripFile(appBase);
9289
9290  parseAbsoluteUrl(appBase, this, appBase);
9291
9292
9293  /**
9294   * Parse given hashbang url into properties
9295   * @param {string} url Hashbang url
9296   * @private
9297   */
9298  this.$$parse = function(url) {
9299    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9300    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9301        ? beginsWith(hashPrefix, withoutBaseUrl)
9302        : (this.$$html5)
9303          ? withoutBaseUrl
9304          : '';
9305
9306    if (!isString(withoutHashUrl)) {
9307      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9308          hashPrefix);
9309    }
9310    parseAppUrl(withoutHashUrl, this, appBase);
9311
9312    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9313
9314    this.$$compose();
9315
9316    /*
9317     * In Windows, on an anchor node on documents loaded from
9318     * the filesystem, the browser will return a pathname
9319     * prefixed with the drive name ('/C:/path') when a
9320     * pathname without a drive is set:
9321     *  * a.setAttribute('href', '/foo')
9322     *   * a.pathname === '/C:/foo' //true
9323     *
9324     * Inside of Angular, we're always using pathnames that
9325     * do not include drive names for routing.
9326     */
9327    function removeWindowsDriveName (path, url, base) {
9328      /*
9329      Matches paths for file protocol on windows,
9330      such as /C:/foo/bar, and captures only /foo/bar.
9331      */
9332      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
9333
9334      var firstPathSegmentMatch;
9335
9336      //Get the relative path from the input URL.
9337      if (url.indexOf(base) === 0) {
9338        url = url.replace(base, '');
9339      }
9340
9341      // The input URL intentionally contains a first path segment that ends with a colon.
9342      if (windowsFilePathExp.exec(url)) {
9343        return path;
9344      }
9345
9346      firstPathSegmentMatch = windowsFilePathExp.exec(path);
9347      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9348    }
9349  };
9350
9351  /**
9352   * Compose hashbang url and update `absUrl` property
9353   * @private
9354   */
9355  this.$$compose = function() {
9356    var search = toKeyValue(this.$$search),
9357        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9358
9359    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9360    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9361  };
9362
9363  this.$$rewrite = function(url) {
9364    if(stripHash(appBase) == stripHash(url)) {
9365      return url;
9366    }
9367  };
9368}
9369
9370
9371/**
9372 * LocationHashbangUrl represents url
9373 * This object is exposed as $location service when html5 history api is enabled but the browser
9374 * does not support it.
9375 *
9376 * @constructor
9377 * @param {string} appBase application base URL
9378 * @param {string} hashPrefix hashbang prefix
9379 */
9380function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9381  this.$$html5 = true;
9382  LocationHashbangUrl.apply(this, arguments);
9383
9384  var appBaseNoFile = stripFile(appBase);
9385
9386  this.$$rewrite = function(url) {
9387    var appUrl;
9388
9389    if ( appBase == stripHash(url) ) {
9390      return url;
9391    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
9392      return appBase + hashPrefix + appUrl;
9393    } else if ( appBaseNoFile === url + '/') {
9394      return appBaseNoFile;
9395    }
9396  };
9397
9398  this.$$compose = function() {
9399    var search = toKeyValue(this.$$search),
9400        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9401
9402    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9403    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
9404    this.$$absUrl = appBase + hashPrefix + this.$$url;
9405  };
9406
9407}
9408
9409
9410LocationHashbangInHtml5Url.prototype =
9411  LocationHashbangUrl.prototype =
9412  LocationHtml5Url.prototype = {
9413
9414  /**
9415   * Are we in html5 mode?
9416   * @private
9417   */
9418  $$html5: false,
9419
9420  /**
9421   * Has any change been replacing ?
9422   * @private
9423   */
9424  $$replace: false,
9425
9426  /**
9427   * @ngdoc method
9428   * @name $location#absUrl
9429   *
9430   * @description
9431   * This method is getter only.
9432   *
9433   * Return full url representation with all segments encoded according to rules specified in
9434   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9435   *
9436   * @return {string} full url
9437   */
9438  absUrl: locationGetter('$$absUrl'),
9439
9440  /**
9441   * @ngdoc method
9442   * @name $location#url
9443   *
9444   * @description
9445   * This method is getter / setter.
9446   *
9447   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9448   *
9449   * Change path, search and hash, when called with parameter and return `$location`.
9450   *
9451   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9452   * @param {string=} replace The path that will be changed
9453   * @return {string} url
9454   */
9455  url: function(url, replace) {
9456    if (isUndefined(url))
9457      return this.$$url;
9458
9459    var match = PATH_MATCH.exec(url);
9460    if (match[1]) this.path(decodeURIComponent(match[1]));
9461    if (match[2] || match[1]) this.search(match[3] || '');
9462    this.hash(match[5] || '', replace);
9463
9464    return this;
9465  },
9466
9467  /**
9468   * @ngdoc method
9469   * @name $location#protocol
9470   *
9471   * @description
9472   * This method is getter only.
9473   *
9474   * Return protocol of current url.
9475   *
9476   * @return {string} protocol of current url
9477   */
9478  protocol: locationGetter('$$protocol'),
9479
9480  /**
9481   * @ngdoc method
9482   * @name $location#host
9483   *
9484   * @description
9485   * This method is getter only.
9486   *
9487   * Return host of current url.
9488   *
9489   * @return {string} host of current url.
9490   */
9491  host: locationGetter('$$host'),
9492
9493  /**
9494   * @ngdoc method
9495   * @name $location#port
9496   *
9497   * @description
9498   * This method is getter only.
9499   *
9500   * Return port of current url.
9501   *
9502   * @return {Number} port
9503   */
9504  port: locationGetter('$$port'),
9505
9506  /**
9507   * @ngdoc method
9508   * @name $location#path
9509   *
9510   * @description
9511   * This method is getter / setter.
9512   *
9513   * Return path of current url when called without any parameter.
9514   *
9515   * Change path when called with parameter and return `$location`.
9516   *
9517   * Note: Path should always begin with forward slash (/), this method will add the forward slash
9518   * if it is missing.
9519   *
9520   * @param {string=} path New path
9521   * @return {string} path
9522   */
9523  path: locationGetterSetter('$$path', function(path) {
9524    return path.charAt(0) == '/' ? path : '/' + path;
9525  }),
9526
9527  /**
9528   * @ngdoc method
9529   * @name $location#search
9530   *
9531   * @description
9532   * This method is getter / setter.
9533   *
9534   * Return search part (as object) of current url when called without any parameter.
9535   *
9536   * Change search part when called with parameter and return `$location`.
9537   *
9538   *
9539   * ```js
9540   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
9541   * var searchObject = $location.search();
9542   * // => {foo: 'bar', baz: 'xoxo'}
9543   *
9544   *
9545   * // set foo to 'yipee'
9546   * $location.search('foo', 'yipee');
9547   * // => $location
9548   * ```
9549   *
9550   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9551   * hash object.
9552   *
9553   * When called with a single argument the method acts as a setter, setting the `search` component
9554   * of `$location` to the specified value.
9555   *
9556   * If the argument is a hash object containing an array of values, these values will be encoded
9557   * as duplicate search parameters in the url.
9558   *
9559   * @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
9560   * will override only a single search property.
9561   *
9562   * If `paramValue` is an array, it will override the property of the `search` component of
9563   * `$location` specified via the first argument.
9564   *
9565   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
9566   *
9567   * If `paramValue` is `true`, the property specified via the first argument will be added with no
9568   * value nor trailing equal sign.
9569   *
9570   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
9571   * one or more arguments returns `$location` object itself.
9572   */
9573  search: function(search, paramValue) {
9574    switch (arguments.length) {
9575      case 0:
9576        return this.$$search;
9577      case 1:
9578        if (isString(search)) {
9579          this.$$search = parseKeyValue(search);
9580        } else if (isObject(search)) {
9581          // remove object undefined or null properties
9582          forEach(search, function(value, key) {
9583            if (value == null) delete search[key];
9584          });
9585
9586          this.$$search = search;
9587        } else {
9588          throw $locationMinErr('isrcharg',
9589              'The first argument of the `$location#search()` call must be a string or an object.');
9590        }
9591        break;
9592      default:
9593        if (isUndefined(paramValue) || paramValue === null) {
9594          delete this.$$search[search];
9595        } else {
9596          this.$$search[search] = paramValue;
9597        }
9598    }
9599
9600    this.$$compose();
9601    return this;
9602  },
9603
9604  /**
9605   * @ngdoc method
9606   * @name $location#hash
9607   *
9608   * @description
9609   * This method is getter / setter.
9610   *
9611   * Return hash fragment when called without any parameter.
9612   *
9613   * Change hash fragment when called with parameter and return `$location`.
9614   *
9615   * @param {string=} hash New hash fragment
9616   * @return {string} hash
9617   */
9618  hash: locationGetterSetter('$$hash', identity),
9619
9620  /**
9621   * @ngdoc method
9622   * @name $location#replace
9623   *
9624   * @description
9625   * If called, all changes to $location during current `$digest` will be replacing current history
9626   * record, instead of adding new one.
9627   */
9628  replace: function() {
9629    this.$$replace = true;
9630    return this;
9631  }
9632};
9633
9634function locationGetter(property) {
9635  return function() {
9636    return this[property];
9637  };
9638}
9639
9640
9641function locationGetterSetter(property, preprocess) {
9642  return function(value) {
9643    if (isUndefined(value))
9644      return this[property];
9645
9646    this[property] = preprocess(value);
9647    this.$$compose();
9648
9649    return this;
9650  };
9651}
9652
9653
9654/**
9655 * @ngdoc service
9656 * @name $location
9657 *
9658 * @requires $rootElement
9659 *
9660 * @description
9661 * The $location service parses the URL in the browser address bar (based on the
9662 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9663 * available to your application. Changes to the URL in the address bar are reflected into
9664 * $location service and changes to $location are reflected into the browser address bar.
9665 *
9666 * **The $location service:**
9667 *
9668 * - Exposes the current URL in the browser address bar, so you can
9669 *   - Watch and observe the URL.
9670 *   - Change the URL.
9671 * - Synchronizes the URL with the browser when the user
9672 *   - Changes the address bar.
9673 *   - Clicks the back or forward button (or clicks a History link).
9674 *   - Clicks on a link.
9675 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9676 *
9677 * For more information see {@link guide/$location Developer Guide: Using $location}
9678 */
9679
9680/**
9681 * @ngdoc provider
9682 * @name $locationProvider
9683 * @description
9684 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9685 */
9686function $LocationProvider(){
9687  var hashPrefix = '',
9688      html5Mode = false;
9689
9690  /**
9691   * @ngdoc method
9692   * @name $locationProvider#hashPrefix
9693   * @description
9694   * @param {string=} prefix Prefix for hash part (containing path and search)
9695   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9696   */
9697  this.hashPrefix = function(prefix) {
9698    if (isDefined(prefix)) {
9699      hashPrefix = prefix;
9700      return this;
9701    } else {
9702      return hashPrefix;
9703    }
9704  };
9705
9706  /**
9707   * @ngdoc method
9708   * @name $locationProvider#html5Mode
9709   * @description
9710   * @param {boolean=} mode Use HTML5 strategy if available.
9711   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9712   */
9713  this.html5Mode = function(mode) {
9714    if (isDefined(mode)) {
9715      html5Mode = mode;
9716      return this;
9717    } else {
9718      return html5Mode;
9719    }
9720  };
9721
9722  /**
9723   * @ngdoc event
9724   * @name $location#$locationChangeStart
9725   * @eventType broadcast on root scope
9726   * @description
9727   * Broadcasted before a URL will change. This change can be prevented by calling
9728   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9729   * details about event object. Upon successful change
9730   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9731   *
9732   * @param {Object} angularEvent Synthetic event object.
9733   * @param {string} newUrl New URL
9734   * @param {string=} oldUrl URL that was before it was changed.
9735   */
9736
9737  /**
9738   * @ngdoc event
9739   * @name $location#$locationChangeSuccess
9740   * @eventType broadcast on root scope
9741   * @description
9742   * Broadcasted after a URL was changed.
9743   *
9744   * @param {Object} angularEvent Synthetic event object.
9745   * @param {string} newUrl New URL
9746   * @param {string=} oldUrl URL that was before it was changed.
9747   */
9748
9749  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9750      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9751    var $location,
9752        LocationMode,
9753        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9754        initialUrl = $browser.url(),
9755        appBase;
9756
9757    if (html5Mode) {
9758      appBase = serverBase(initialUrl) + (baseHref || '/');
9759      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9760    } else {
9761      appBase = stripHash(initialUrl);
9762      LocationMode = LocationHashbangUrl;
9763    }
9764    $location = new LocationMode(appBase, '#' + hashPrefix);
9765    $location.$$parse($location.$$rewrite(initialUrl));
9766
9767    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
9768
9769    $rootElement.on('click', function(event) {
9770      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9771      // currently we open nice url link and redirect then
9772
9773      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9774
9775      var elm = jqLite(event.target);
9776
9777      // traverse the DOM up to find first A tag
9778      while (lowercase(elm[0].nodeName) !== 'a') {
9779        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9780        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9781      }
9782
9783      var absHref = elm.prop('href');
9784
9785      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9786        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9787        // an animation.
9788        absHref = urlResolve(absHref.animVal).href;
9789      }
9790
9791      // Ignore when url is started with javascript: or mailto:
9792      if (IGNORE_URI_REGEXP.test(absHref)) return;
9793
9794      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
9795      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
9796      // somewhere#anchor or http://example.com/somewhere
9797      if (LocationMode === LocationHashbangInHtml5Url) {
9798        // get the actual href attribute - see
9799        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9800        var href = elm.attr('href') || elm.attr('xlink:href');
9801
9802        if (href.indexOf('://') < 0) {         // Ignore absolute URLs
9803          var prefix = '#' + hashPrefix;
9804          if (href[0] == '/') {
9805            // absolute path - replace old path
9806            absHref = appBase + prefix + href;
9807          } else if (href[0] == '#') {
9808            // local anchor
9809            absHref = appBase + prefix + ($location.path() || '/') + href;
9810          } else {
9811            // relative path - join with current path
9812            var stack = $location.path().split("/"),
9813              parts = href.split("/");
9814            for (var i=0; i<parts.length; i++) {
9815              if (parts[i] == ".")
9816                continue;
9817              else if (parts[i] == "..")
9818                stack.pop();
9819              else if (parts[i].length)
9820                stack.push(parts[i]);
9821            }
9822            absHref = appBase + prefix + stack.join('/');
9823          }
9824        }
9825      }
9826
9827      var rewrittenUrl = $location.$$rewrite(absHref);
9828
9829      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9830        event.preventDefault();
9831        if (rewrittenUrl != $browser.url()) {
9832          // update location manually
9833          $location.$$parse(rewrittenUrl);
9834          $rootScope.$apply();
9835          // hack to work around FF6 bug 684208 when scenario runner clicks on links
9836          window.angular['ff-684208-preventDefault'] = true;
9837        }
9838      }
9839    });
9840
9841
9842    // rewrite hashbang url <> html5 url
9843    if ($location.absUrl() != initialUrl) {
9844      $browser.url($location.absUrl(), true);
9845    }
9846
9847    // update $location when $browser url changes
9848    $browser.onUrlChange(function(newUrl) {
9849      if ($location.absUrl() != newUrl) {
9850        $rootScope.$evalAsync(function() {
9851          var oldUrl = $location.absUrl();
9852
9853          $location.$$parse(newUrl);
9854          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9855                                    oldUrl).defaultPrevented) {
9856            $location.$$parse(oldUrl);
9857            $browser.url(oldUrl);
9858          } else {
9859            afterLocationChange(oldUrl);
9860          }
9861        });
9862        if (!$rootScope.$$phase) $rootScope.$digest();
9863      }
9864    });
9865
9866    // update browser
9867    var changeCounter = 0;
9868    $rootScope.$watch(function $locationWatch() {
9869      var oldUrl = $browser.url();
9870      var currentReplace = $location.$$replace;
9871
9872      if (!changeCounter || oldUrl != $location.absUrl()) {
9873        changeCounter++;
9874        $rootScope.$evalAsync(function() {
9875          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9876              defaultPrevented) {
9877            $location.$$parse(oldUrl);
9878          } else {
9879            $browser.url($location.absUrl(), currentReplace);
9880            afterLocationChange(oldUrl);
9881          }
9882        });
9883      }
9884      $location.$$replace = false;
9885
9886      return changeCounter;
9887    });
9888
9889    return $location;
9890
9891    function afterLocationChange(oldUrl) {
9892      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9893    }
9894}];
9895}
9896
9897/**
9898 * @ngdoc service
9899 * @name $log
9900 * @requires $window
9901 *
9902 * @description
9903 * Simple service for logging. Default implementation safely writes the message
9904 * into the browser's console (if present).
9905 *
9906 * The main purpose of this service is to simplify debugging and troubleshooting.
9907 *
9908 * The default is to log `debug` messages. You can use
9909 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9910 *
9911 * @example
9912   <example module="logExample">
9913     <file name="script.js">
9914       angular.module('logExample', [])
9915         .controller('LogController', ['$scope', '$log', function($scope, $log) {
9916           $scope.$log = $log;
9917           $scope.message = 'Hello World!';
9918         }]);
9919     </file>
9920     <file name="index.html">
9921       <div ng-controller="LogController">
9922         <p>Reload this page with open console, enter text and hit the log button...</p>
9923         Message:
9924         <input type="text" ng-model="message"/>
9925         <button ng-click="$log.log(message)">log</button>
9926         <button ng-click="$log.warn(message)">warn</button>
9927         <button ng-click="$log.info(message)">info</button>
9928         <button ng-click="$log.error(message)">error</button>
9929       </div>
9930     </file>
9931   </example>
9932 */
9933
9934/**
9935 * @ngdoc provider
9936 * @name $logProvider
9937 * @description
9938 * Use the `$logProvider` to configure how the application logs messages
9939 */
9940function $LogProvider(){
9941  var debug = true,
9942      self = this;
9943
9944  /**
9945   * @ngdoc method
9946   * @name $logProvider#debugEnabled
9947   * @description
9948   * @param {boolean=} flag enable or disable debug level messages
9949   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9950   */
9951  this.debugEnabled = function(flag) {
9952    if (isDefined(flag)) {
9953      debug = flag;
9954    return this;
9955    } else {
9956      return debug;
9957    }
9958  };
9959
9960  this.$get = ['$window', function($window){
9961    return {
9962      /**
9963       * @ngdoc method
9964       * @name $log#log
9965       *
9966       * @description
9967       * Write a log message
9968       */
9969      log: consoleLog('log'),
9970
9971      /**
9972       * @ngdoc method
9973       * @name $log#info
9974       *
9975       * @description
9976       * Write an information message
9977       */
9978      info: consoleLog('info'),
9979
9980      /**
9981       * @ngdoc method
9982       * @name $log#warn
9983       *
9984       * @description
9985       * Write a warning message
9986       */
9987      warn: consoleLog('warn'),
9988
9989      /**
9990       * @ngdoc method
9991       * @name $log#error
9992       *
9993       * @description
9994       * Write an error message
9995       */
9996      error: consoleLog('error'),
9997
9998      /**
9999       * @ngdoc method
10000       * @name $log#debug
10001       *
10002       * @description
10003       * Write a debug message
10004       */
10005      debug: (function () {
10006        var fn = consoleLog('debug');
10007
10008        return function() {
10009          if (debug) {
10010            fn.apply(self, arguments);
10011          }
10012        };
10013      }())
10014    };
10015
10016    function formatError(arg) {
10017      if (arg instanceof Error) {
10018        if (arg.stack) {
10019          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
10020              ? 'Error: ' + arg.message + '\n' + arg.stack
10021              : arg.stack;
10022        } else if (arg.sourceURL) {
10023          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
10024        }
10025      }
10026      return arg;
10027    }
10028
10029    function consoleLog(type) {
10030      var console = $window.console || {},
10031          logFn = console[type] || console.log || noop,
10032          hasApply = false;
10033
10034      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
10035      // The reason behind this is that console.log has type "object" in IE8...
10036      try {
10037        hasApply = !!logFn.apply;
10038      } catch (e) {}
10039
10040      if (hasApply) {
10041        return function() {
10042          var args = [];
10043          forEach(arguments, function(arg) {
10044            args.push(formatError(arg));
10045          });
10046          return logFn.apply(console, args);
10047        };
10048      }
10049
10050      // we are IE which either doesn't have window.console => this is noop and we do nothing,
10051      // or we are IE where console.log doesn't have apply so we log at least first 2 args
10052      return function(arg1, arg2) {
10053        logFn(arg1, arg2 == null ? '' : arg2);
10054      };
10055    }
10056  }];
10057}
10058
10059var $parseMinErr = minErr('$parse');
10060var promiseWarningCache = {};
10061var promiseWarning;
10062
10063// Sandboxing Angular Expressions
10064// ------------------------------
10065// Angular expressions are generally considered safe because these expressions only have direct
10066// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
10067// obtaining a reference to native JS functions such as the Function constructor.
10068//
10069// As an example, consider the following Angular expression:
10070//
10071//   {}.toString.constructor('alert("evil JS code")')
10072//
10073// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
10074// against the expression language, but not to prevent exploits that were enabled by exposing
10075// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
10076// practice and therefore we are not even trying to protect against interaction with an object
10077// explicitly exposed in this way.
10078//
10079// In general, it is not possible to access a Window object from an angular expression unless a
10080// window or some DOM object that has a reference to window is published onto a Scope.
10081// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
10082// native objects.
10083
10084
10085function ensureSafeMemberName(name, fullExpression) {
10086  if (name === "__defineGetter__" || name === "__defineSetter__"
10087      || name === "__lookupGetter__" || name === "__lookupSetter__"
10088      || name === "__proto__") {
10089    throw $parseMinErr('isecfld',
10090        'Attempting to access a disallowed field in Angular expressions! '
10091        +'Expression: {0}', fullExpression);
10092  }
10093  return name;
10094}
10095
10096function ensureSafeObject(obj, fullExpression) {
10097  // nifty check if obj is Function that is fast and works across iframes and other contexts
10098  if (obj) {
10099    if (obj.constructor === obj) {
10100      throw $parseMinErr('isecfn',
10101          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10102          fullExpression);
10103    } else if (// isWindow(obj)
10104        obj.document && obj.location && obj.alert && obj.setInterval) {
10105      throw $parseMinErr('isecwindow',
10106          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
10107          fullExpression);
10108    } else if (// isElement(obj)
10109        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
10110      throw $parseMinErr('isecdom',
10111          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
10112          fullExpression);
10113    } else if (// block Object so that we can't get hold of dangerous Object.* methods
10114        obj === Object) {
10115      throw $parseMinErr('isecobj',
10116          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
10117          fullExpression);
10118    }
10119  }
10120  return obj;
10121}
10122
10123var CALL = Function.prototype.call;
10124var APPLY = Function.prototype.apply;
10125var BIND = Function.prototype.bind;
10126
10127function ensureSafeFunction(obj, fullExpression) {
10128  if (obj) {
10129    if (obj.constructor === obj) {
10130      throw $parseMinErr('isecfn',
10131        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10132        fullExpression);
10133    } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)
10133) {
10134      throw $parseMinErr('isecff',
10135        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
10136        fullExpression);
10137    }
10138  }
10139}
10140
10141var OPERATORS = {
10142    /* jshint bitwise : false */
10143    'null':function(){return null;},
10144    'true':function(){return true;},
10145    'false':function(){return false;},
10146    undefined:noop,
10147    '+':function(self, locals, a,b){
10148      a=a(self, locals); b=b(self, locals);
10149      if (isDefined(a)) {
10150        if (isDefined(b)) {
10151          return a + b;
10152        }
10153        return a;
10154      }
10155      return isDefined(b)?b:undefined;},
10156    '-':function(self, locals, a,b){
10157          a=a(self, locals); b=b(self, locals);
10158          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
10159        },
10160    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
10161    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
10162    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
10163    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
10164    '=':noop,
10165    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
10166    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
10167    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
10168    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
10169    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
10170    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
10171    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
10172    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
10173    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
10174    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
10175    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
10176//    '|':function(self, locals, a,b){return a|b;},
10177    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
10178    '!':function(self, locals, a){return !a(self, locals);}
10179};
10180/* jshint bitwise: true */
10181var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
10182
10183
10184/////////////////////////////////////////
10185
10186
10187/**
10188 * @constructor
10189 */
10190var Lexer = function (options) {
10191  this.options = options;
10192};
10193
10194Lexer.prototype = {
10195  constructor: Lexer,
10196
10197  lex: function (text) {
10198    this.text = text;
10199
10200    this.index = 0;
10201    this.ch = undefined;
10202    this.lastCh = ':'; // can start regexp
10203
10204    this.tokens = [];
10205
10206    while (this.index < this.text.length) {
10207      this.ch = this.text.charAt(this.index);
10208      if (this.is('"\'')) {
10209        this.readString(this.ch);
10210      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
10211        this.readNumber();
10212      } else if (this.isIdent(this.ch)) {
10213        this.readIdent();
10214      } else if (this.is('(){}[].,;:?')) {
10215        this.tokens.push({
10216          index: this.index,
10217          text: this.ch
10218        });
10219        this.index++;
10220      } else if (this.isWhitespace(this.ch)) {
10221        this.index++;
10222        continue;
10223      } else {
10224        var ch2 = this.ch + this.peek();
10225        var ch3 = ch2 + this.peek(2);
10226        var fn = OPERATORS[this.ch];
10227        var fn2 = OPERATORS[ch2];
10228        var fn3 = OPERATORS[ch3];
10229        if (fn3) {
10230          this.tokens.push({index: this.index, text: ch3, fn: fn3});
10231          this.index += 3;
10232        } else if (fn2) {
10233          this.tokens.push({index: this.index, text: ch2, fn: fn2});
10234          this.index += 2;
10235        } else if (fn) {
10236          this.tokens.push({
10237            index: this.index,
10238            text: this.ch,
10239            fn: fn
10240          });
10241          this.index += 1;
10242        } else {
10243          this.throwError('Unexpected next character ', this.index, this.index + 1);
10244        }
10245      }
10246      this.lastCh = this.ch;
10247    }
10248    return this.tokens;
10249  },
10250
10251  is: function(chars) {
10252    return chars.indexOf(this.ch) !== -1;
10253  },
10254
10255  was: function(chars) {
10256    return chars.indexOf(this.lastCh) !== -1;
10257  },
10258
10259  peek: function(i) {
10260    var num = i || 1;
10261    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
10262  },
10263
10264  isNumber: function(ch) {
10265    return ('0' <= ch && ch <= '9');
10266  },
10267
10268  isWhitespace: function(ch) {
10269    // IE treats non-breaking space as \u00A0
10270    return (ch === ' ' || ch === '\r' || ch === '\t' ||
10271            ch === '\n' || ch === '\v' || ch === '\u00A0');
10272  },
10273
10274  isIdent: function(ch) {
10275    return ('a' <= ch && ch <= 'z' ||
10276            'A' <= ch && ch <= 'Z' ||
10277            '_' === ch || ch === '$');
10278  },
10279
10280  isExpOperator: function(ch) {
10281    return (ch === '-' || ch === '+' || this.isNumber(ch));
10282  },
10283
10284  throwError: function(error, start, end) {
10285    end = end || this.index;
10286    var colStr = (isDefined(start)
10287            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10288            : ' ' + end);
10289    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10290        error, colStr, this.text);
10291  },
10292
10293  readNumber: function() {
10294    var number = '';
10295    var start = this.index;
10296    while (this.index < this.text.length) {
10297      var ch = lowercase(this.text.charAt(this.index));
10298      if (ch == '.' || this.isNumber(ch)) {
10299        number += ch;
10300      } else {
10301        var peekCh = this.peek();
10302        if (ch == 'e' && this.isExpOperator(peekCh)) {
10303          number += ch;
10304        } else if (this.isExpOperator(ch) &&
10305            peekCh && this.isNumber(peekCh) &&
10306            number.charAt(number.length - 1) == 'e') {
10307          number += ch;
10308        } else if (this.isExpOperator(ch) &&
10309            (!peekCh || !this.isNumber(peekCh)) &&
10310            number.charAt(number.length - 1) == 'e') {
10311          this.throwError('Invalid exponent');
10312        } else {
10313          break;
10314        }
10315      }
10316      this.index++;
10317    }
10318    number = 1 * number;
10319    this.tokens.push({
10320      index: start,
10321      text: number,
10322      literal: true,
10323      constant: true,
10324      fn: function() { return number; }
10325    });
10326  },
10327
10328  readIdent: function() {
10329    var parser = this;
10330
10331    var ident = '';
10332    var start = this.index;
10333
10334    var lastDot, peekIndex, methodName, ch;
10335
10336    while (this.index < this.text.length) {
10337      ch = this.text.charAt(this.index);
10338      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10339        if (ch === '.') lastDot = this.index;
10340        ident += ch;
10341      } else {
10342        break;
10343      }
10344      this.index++;
10345    }
10346
10347    //check if this is not a method invocation and if it is back out to last dot
10348    if (lastDot) {
10349      peekIndex = this.index;
10350      while (peekIndex < this.text.length) {
10351        ch = this.text.charAt(peekIndex);
10352        if (ch === '(') {
10353          methodName = ident.substr(lastDot - start + 1);
10354          ident = ident.substr(0, lastDot - start);
10355          this.index = peekIndex;
10356          break;
10357        }
10358        if (this.isWhitespace(ch)) {
10359          peekIndex++;
10360        } else {
10361          break;
10362        }
10363      }
10364    }
10365
10366
10367    var token = {
10368      index: start,
10369      text: ident
10370    };
10371
10372    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10373    if (OPERATORS.hasOwnProperty(ident)) {
10374      token.fn = OPERATORS[ident];
10375      token.literal = true;
10376      token.constant = true;
10377    } else {
10378      var getter = getterFn(ident, this.options, this.text);
10379      token.fn = extend(function(self, locals) {
10380        return (getter(self, locals));
10381      }, {
10382        assign: function(self, value) {
10383          return setter(self, ident, value, parser.text, parser.options);
10384        }
10385      });
10386    }
10387
10388    this.tokens.push(token);
10389
10390    if (methodName) {
10391      this.tokens.push({
10392        index:lastDot,
10393        text: '.'
10394      });
10395      this.tokens.push({
10396        index: lastDot + 1,
10397        text: methodName
10398      });
10399    }
10400  },
10401
10402  readString: function(quote) {
10403    var start = this.index;
10404    this.index++;
10405    var string = '';
10406    var rawString = quote;
10407    var escape = false;
10408    while (this.index < this.text.length) {
10409      var ch = this.text.charAt(this.index);
10410      rawString += ch;
10411      if (escape) {
10412        if (ch === 'u') {
10413          var hex = this.text.substring(this.index + 1, this.index + 5);
10414          if (!hex.match(/[\da-f]{4}/i))
10415            this.throwError('Invalid unicode escape [\\u' + hex + ']');
10416          this.index += 4;
10417          string += String.fromCharCode(parseInt(hex, 16));
10418        } else {
10419          var rep = ESCAPE[ch];
10420          string = string + (rep || ch);
10421        }
10422        escape = false;
10423      } else if (ch === '\\') {
10424        escape = true;
10425      } else if (ch === quote) {
10426        this.index++;
10427        this.tokens.push({
10428          index: start,
10429          text: rawString,
10430          string: string,
10431          literal: true,
10432          constant: true,
10433          fn: function() { return string; }
10434        });
10435        return;
10436      } else {
10437        string += ch;
10438      }
10439      this.index++;
10440    }
10441    this.throwError('Unterminated quote', start);
10442  }
10443};
10444
10445
10446/**
10447 * @constructor
10448 */
10449var Parser = function (lexer, $filter, options) {
10450  this.lexer = lexer;
10451  this.$filter = $filter;
10452  this.options = options;
10453};
10454
10455Parser.ZERO = extend(function () {
10456  return 0;
10457}, {
10458  constant: true
10459});
10460
10461Parser.prototype = {
10462  constructor: Parser,
10463
10464  parse: function (text) {
10465    this.text = text;
10466
10467    this.tokens = this.lexer.lex(text);
10468
10469    var value = this.statements();
10470
10471    if (this.tokens.length !== 0) {
10472      this.throwError('is an unexpected token', this.tokens[0]);
10473    }
10474
10475    value.literal = !!value.literal;
10476    value.constant = !!value.constant;
10477
10478    return value;
10479  },
10480
10481  primary: function () {
10482    var primary;
10483    if (this.expect('(')) {
10484      primary = this.filterChain();
10485      this.consume(')');
10486    } else if (this.expect('[')) {
10487      primary = this.arrayDeclaration();
10488    } else if (this.expect('{')) {
10489      primary = this.object();
10490    } else {
10491      var token = this.expect();
10492      primary = token.fn;
10493      if (!primary) {
10494        this.throwError('not a primary expression', token);
10495      }
10496      primary.literal = !!token.literal;
10497      primary.constant = !!token.constant;
10498    }
10499
10500    var next, context;
10501    while ((next = this.expect('(', '[', '.'))) {
10502      if (next.text === '(') {
10503        primary = this.functionCall(primary, context);
10504        context = null;
10505      } else if (next.text === '[') {
10506        context = primary;
10507        primary = this.objectIndex(primary);
10508      } else if (next.text === '.') {
10509        context = primary;
10510        primary = this.fieldAccess(primary);
10511      } else {
10512        this.throwError('IMPOSSIBLE');
10513      }
10514    }
10515    return primary;
10516  },
10517
10518  throwError: function(msg, token) {
10519    throw $parseMinErr('syntax',
10520        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10521          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10522  },
10523
10524  peekToken: function() {
10525    if (this.tokens.length === 0)
10526      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10527    return this.tokens[0];
10528  },
10529
10530  peek: function(e1, e2, e3, e4) {
10531    if (this.tokens.length > 0) {
10532      var token = this.tokens[0];
10533      var t = token.text;
10534      if (t === e1 || t === e2 || t === e3 || t === e4 ||
10535          (!e1 && !e2 && !e3 && !e4)) {
10536        return token;
10537      }
10538    }
10539    return false;
10540  },
10541
10542  expect: function(e1, e2, e3, e4){
10543    var token = this.peek(e1, e2, e3, e4);
10544    if (token) {
10545      this.tokens.shift();
10546      return token;
10547    }
10548    return false;
10549  },
10550
10551  consume: function(e1){
10552    if (!this.expect(e1)) {
10553      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10554    }
10555  },
10556
10557  unaryFn: function(fn, right) {
10558    return extend(function(self, locals) {
10559      return fn(self, locals, right);
10560    }, {
10561      constant:right.constant
10562    });
10563  },
10564
10565  ternaryFn: function(left, middle, right){
10566    return extend(function(self, locals){
10567      return left(self, locals) ? middle(self, locals) : right(self, locals);
10568    }, {
10569      constant: left.constant && middle.constant && right.constant
10570    });
10571  },
10572
10573  binaryFn: function(left, fn, right) {
10574    return extend(function(self, locals) {
10575      return fn(self, locals, left, right);
10576    }, {
10577      constant:left.constant && right.constant
10578    });
10579  },
10580
10581  statements: function() {
10582    var statements = [];
10583    while (true) {
10584      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10585        statements.push(this.filterChain());
10586      if (!this.expect(';')) {
10587        // optimize for the common case where there is only one statement.
10588        // TODO(size): maybe we should not support multiple statements?
10589        return (statements.length === 1)
10590            ? statements[0]
10591            : function(self, locals) {
10592                var value;
10593                for (var i = 0; i < statements.length; i++) {
10594                  var statement = statements[i];
10595                  if (statement) {
10596                    value = statement(self, locals);
10597                  }
10598                }
10599                return value;
10600              };
10601      }
10602    }
10603  },
10604
10605  filterChain: function() {
10606    var left = this.expression();
10607    var token;
10608    while (true) {
10609      if ((token = this.expect('|'))) {
10610        left = this.binaryFn(left, token.fn, this.filter());
10611      } else {
10612        return left;
10613      }
10614    }
10615  },
10616
10617  filter: function() {
10618    var token = this.expect();
10619    var fn = this.$filter(token.text);
10620    var argsFn = [];
10621    while (true) {
10622      if ((token = this.expect(':'))) {
10623        argsFn.push(this.expression());
10624      } else {
10625        var fnInvoke = function(self, locals, input) {
10626          var args = [input];
10627          for (var i = 0; i < argsFn.length; i++) {
10628            args.push(argsFn[i](self, locals));
10629          }
10630          return fn.apply(self, args);
10631        };
10632        return function() {
10633          return fnInvoke;
10634        };
10635      }
10636    }
10637  },
10638
10639  expression: function() {
10640    return this.assignment();
10641  },
10642
10643  assignment: function() {
10644    var left = this.ternary();
10645    var right;
10646    var token;
10647    if ((token = this.expect('='))) {
10648      if (!left.assign) {
10649        this.throwError('implies assignment but [' +
10650            this.text.substring(0, token.index) + '] can not be assigned to', token);
10651      }
10652      right = this.ternary();
10653      return function(scope, locals) {
10654        return left.assign(scope, right(scope, locals), locals);
10655      };
10656    }
10657    return left;
10658  },
10659
10660  ternary: function() {
10661    var left = this.logicalOR();
10662    var middle;
10663    var token;
10664    if ((token = this.expect('?'))) {
10665      middle = this.assignment();
10666      if ((token = this.expect(':'))) {
10667        return this.ternaryFn(left, middle, this.assignment());
10668      } else {
10669        this.throwError('expected :', token);
10670      }
10671    } else {
10672      return left;
10673    }
10674  },
10675
10676  logicalOR: function() {
10677    var left = this.logicalAND();
10678    var token;
10679    while (true) {
10680      if ((token = this.expect('||'))) {
10681        left = this.binaryFn(left, token.fn, this.logicalAND());
10682      } else {
10683        return left;
10684      }
10685    }
10686  },
10687
10688  logicalAND: function() {
10689    var left = this.equality();
10690    var token;
10691    if ((token = this.expect('&&'))) {
10692      left = this.binaryFn(left, token.fn, this.logicalAND());
10693    }
10694    return left;
10695  },
10696
10697  equality: function() {
10698    var left = this.relational();
10699    var token;
10700    if ((token = this.expect('==','!=','===','!=='))) {
10701      left = this.binaryFn(left, token.fn, this.equality());
10702    }
10703    return left;
10704  },
10705
10706  relational: function() {
10707    var left = this.additive();
10708    var token;
10709    if ((token = this.expect('<', '>', '<=', '>='))) {
10710      left = this.binaryFn(left, token.fn, this.relational());
10711    }
10712    return left;
10713  },
10714
10715  additive: function() {
10716    var left = this.multiplicative();
10717    var token;
10718    while ((token = this.expect('+','-'))) {
10719      left = this.binaryFn(left, token.fn, this.multiplicative());
10720    }
10721    return left;
10722  },
10723
10724  multiplicative: function() {
10725    var left = this.unary();
10726    var token;
10727    while ((token = this.expect('*','/','%'))) {
10728      left = this.binaryFn(left, token.fn, this.unary());
10729    }
10730    return left;
10731  },
10732
10733  unary: function() {
10734    var token;
10735    if (this.expect('+')) {
10736      return this.primary();
10737    } else if ((token = this.expect('-'))) {
10738      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10739    } else if ((token = this.expect('!'))) {
10740      return this.unaryFn(token.fn, this.unary());
10741    } else {
10742      return this.primary();
10743    }
10744  },
10745
10746  fieldAccess: function(object) {
10747    var parser = this;
10748    var field = this.expect().text;
10749    var getter = getterFn(field, this.options, this.text);
10750
10751    return extend(function(scope, locals, self) {
10752      return getter(self || object(scope, locals));
10753    }, {
10754      assign: function(scope, value, locals) {
10755        var o = object(scope, locals);
10756        if (!o) object.assign(scope, o = {});
10757        return setter(o, field, value, parser.text, parser.options);
10758      }
10759    });
10760  },
10761
10762  objectIndex: function(obj) {
10763    var parser = this;
10764
10765    var indexFn = this.expression();
10766    this.consume(']');
10767
10768    return extend(function(self, locals) {
10769      var o = obj(self, locals),
10770          i = indexFn(self, locals),
10771          v, p;
10772
10773      ensureSafeMemberName(i, parser.text);
10774      if (!o) return undefined;
10775      v = ensureSafeObject(o[i], parser.text);
10776      if (v && v.then && parser.options.unwrapPromises) {
10777        p = v;
10778        if (!('$$v' in v)) {
10779          p.$$v = undefined;
10780          p.then(function(val) { p.$$v = val; });
10781        }
10782        v = v.$$v;
10783      }
10784      return v;
10785    }, {
10786      assign: function(self, value, locals) {
10787        var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
10788        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10789        var o = ensureSafeObject(obj(self, locals), parser.text);
10790        if (!o) obj.assign(self, o = {});
10791        return o[key] = value;
10792      }
10793    });
10794  },
10795
10796  functionCall: function(fn, contextGetter) {
10797    var argsFn = [];
10798    if (this.peekToken().text !== ')') {
10799      do {
10800        argsFn.push(this.expression());
10801      } while (this.expect(','));
10802    }
10803    this.consume(')');
10804
10805    var parser = this;
10806
10807    return function(scope, locals) {
10808      var args = [];
10809      var context = contextGetter ? contextGetter(scope, locals) : scope;
10810
10811      for (var i = 0; i < argsFn.length; i++) {
10812        args.push(argsFn[i](scope, locals));
10813      }
10814      var fnPtr = fn(scope, locals, context) || noop;
10815
10816      ensureSafeObject(context, parser.text);
10817      ensureSafeFunction(fnPtr, parser.text);
10818
10819      // IE stupidity! (IE doesn't have apply for some native functions)
10820      var v = fnPtr.apply
10821            ? fnPtr.apply(context, args)
10822            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10823
10824      return ensureSafeObject(v, parser.text);
10825    };
10826  },
10827
10828  // This is used with json array declaration
10829  arrayDeclaration: function () {
10830    var elementFns = [];
10831    var allConstant = true;
10832    if (this.peekToken().text !== ']') {
10833      do {
10834        if (this.peek(']')) {
10835          // Support trailing commas per ES5.1.
10836          break;
10837        }
10838        var elementFn = this.expression();
10839        elementFns.push(elementFn);
10840        if (!elementFn.constant) {
10841          allConstant = false;
10842        }
10843      } while (this.expect(','));
10844    }
10845    this.consume(']');
10846
10847    return extend(function(self, locals) {
10848      var array = [];
10849      for (var i = 0; i < elementFns.length; i++) {
10850        array.push(elementFns[i](self, locals));
10851      }
10852      return array;
10853    }, {
10854      literal: true,
10855      constant: allConstant
10856    });
10857  },
10858
10859  object: function () {
10860    var keyValues = [];
10861    var allConstant = true;
10862    if (this.peekToken().text !== '}') {
10863      do {
10864        if (this.peek('}')) {
10865          // Support trailing commas per ES5.1.
10866          break;
10867        }
10868        var token = this.expect(),
10869        key = token.string || token.text;
10870        this.consume(':');
10871        var value = this.expression();
10872        keyValues.push({key: key, value: value});
10873        if (!value.constant) {
10874          allConstant = false;
10875        }
10876      } while (this.expect(','));
10877    }
10878    this.consume('}');
10879
10880    return extend(function(self, locals) {
10881      var object = {};
10882      for (var i = 0; i < keyValues.length; i++) {
10883        var keyValue = keyValues[i];
10884        object[keyValue.key] = keyValue.value(self, locals);
10885      }
10886      return object;
10887    }, {
10888      literal: true,
10889      constant: allConstant
10890    });
10891  }
10892};
10893
10894
10895//////////////////////////////////////////////////
10896// Parser helper functions
10897//////////////////////////////////////////////////
10898
10899function setter(obj, path, setValue, fullExp, options) {
10900  //needed?
10901  options = options || {};
10902
10903  var element = path.split('.'), key;
10904  for (var i = 0; element.length > 1; i++) {
10905    key = ensureSafeMemberName(element.shift(), fullExp);
10906    var propertyObj = obj[key];
10907    if (!propertyObj) {
10908      propertyObj = {};
10909      obj[key] = propertyObj;
10910    }
10911    obj = propertyObj;
10912    if (obj.then && options.unwrapPromises) {
10913      promiseWarning(fullExp);
10914      if (!("$$v" in obj)) {
10915        (function(promise) {
10916          promise.then(function(val) { promise.$$v = val; }); }
10917        )(obj);
10918      }
10919      if (obj.$$v === undefined) {
10920        obj.$$v = {};
10921      }
10922      obj = obj.$$v;
10923    }
10924  }
10925  key = ensureSafeMemberName(element.shift(), fullExp);
10926  ensureSafeObject(obj, fullExp);
10927  ensureSafeObject(obj[key], fullExp);
10928  obj[key] = setValue;
10929  return setValue;
10930}
10931
10932var getterFnCache = {};
10933
10934/**
10935 * Implementation of the "Black Hole" variant from:
10936 * - http://jsperf.com/angularjs-parse-getter/4
10937 * - http://jsperf.com/path-evaluation-simplified/7
10938 */
10939function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10940  ensureSafeMemberName(key0, fullExp);
10941  ensureSafeMemberName(key1, fullExp);
10942  ensureSafeMemberName(key2, fullExp);
10943  ensureSafeMemberName(key3, fullExp);
10944  ensureSafeMemberName(key4, fullExp);
10945
10946  return !options.unwrapPromises
10947      ? function cspSafeGetter(scope, locals) {
10948          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10949
10950          if (pathVal == null) return pathVal;
10951          pathVal = pathVal[key0];
10952
10953          if (!key1) return pathVal;
10954          if (pathVal == null) return undefined;
10955          pathVal = pathVal[key1];
10956
10957          if (!key2) return pathVal;
10958          if (pathVal == null) return undefined;
10959          pathVal = pathVal[key2];
10960
10961          if (!key3) return pathVal;
10962          if (pathVal == null) return undefined;
10963          pathVal = pathVal[key3];
10964
10965          if (!key4) return pathVal;
10966          if (pathVal == null) return undefined;
10967          pathVal = pathVal[key4];
10968
10969          return pathVal;
10970        }
10971      : function cspSafePromiseEnabledGetter(scope, locals) {
10972          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10973              promise;
10974
10975          if (pathVal == null) return pathVal;
10976
10977          pathVal = pathVal[key0];
10978          if (pathVal && pathVal.then) {
10979            promiseWarning(fullExp);
10980            if (!("$$v" in pathVal)) {
10981              promise = pathVal;
10982              promise.$$v = undefined;
10983              promise.then(function(val) { promise.$$v = val; });
10984            }
10985            pathVal = pathVal.$$v;
10986          }
10987
10988          if (!key1) return pathVal;
10989          if (pathVal == null) return undefined;
10990          pathVal = pathVal[key1];
10991          if (pathVal && pathVal.then) {
10992            promiseWarning(fullExp);
10993            if (!("$$v" in pathVal)) {
10994              promise = pathVal;
10995              promise.$$v = undefined;
10996              promise.then(function(val) { promise.$$v = val; });
10997            }
10998            pathVal = pathVal.$$v;
10999          }
11000
11001          if (!key2) return pathVal;
11002          if (pathVal == null) return undefined;
11003          pathVal = pathVal[key2];
11004          if (pathVal && pathVal.then) {
11005            promiseWarning(fullExp);
11006            if (!("$$v" in pathVal)) {
11007              promise = pathVal;
11008              promise.$$v = undefined;
11009              promise.then(function(val) { promise.$$v = val; });
11010            }
11011            pathVal = pathVal.$$v;
11012          }
11013
11014          if (!key3) return pathVal;
11015          if (pathVal == null) return undefined;
11016          pathVal = pathVal[key3];
11017          if (pathVal && pathVal.then) {
11018            promiseWarning(fullExp);
11019            if (!("$$v" in pathVal)) {
11020              promise = pathVal;
11021              promise.$$v = undefined;
11022              promise.then(function(val) { promise.$$v = val; });
11023            }
11024            pathVal = pathVal.$$v;
11025          }
11026
11027          if (!key4) return pathVal;
11028          if (pathVal == null) return undefined;
11029          pathVal = pathVal[key4];
11030          if (pathVal && pathVal.then) {
11031            promiseWarning(fullExp);
11032            if (!("$$v" in pathVal)) {
11033              promise = pathVal;
11034              promise.$$v = undefined;
11035              promise.then(function(val) { promise.$$v = val; });
11036            }
11037            pathVal = pathVal.$$v;
11038          }
11039          return pathVal;
11040        };
11041}
11042
11043function getterFn(path, options, fullExp) {
11044  // Check whether the cache has this getter already.
11045  // We can use hasOwnProperty directly on the cache because we ensure,
11046  // see below, that the cache never stores a path called 'hasOwnProperty'
11047  if (getterFnCache.hasOwnProperty(path)) {
11048    return getterFnCache[path];
11049  }
11050
11051  var pathKeys = path.split('.'),
11052      pathKeysLength = pathKeys.length,
11053      fn;
11054
11055  // http://jsperf.com/angularjs-parse-getter/6
11056  if (options.csp) {
11057    if (pathKeysLength < 6) {
11058      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
11059                          options);
11060    } else {
11061      fn = function(scope, locals) {
11062        var i = 0, val;
11063        do {
11064          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
11065                                pathKeys[i++], fullExp, options)(scope, locals);
11066
11067          locals = undefined; // clear after first iteration
11068          scope = val;
11069        } while (i < pathKeysLength);
11070        return val;
11071      };
11072    }
11073  } else {
11074    var code = 'var p;\n';
11075    forEach(pathKeys, function(key, index) {
11076      ensureSafeMemberName(key, fullExp);
11077      code += 'if(s == null) return undefined;\n' +
11078              's='+ (index
11079                      // we simply dereference 's' on any .dot notation
11080                      ? 's'
11081                      // but if we are first then we check locals first, and if so read it first
11082                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
11083              (options.unwrapPromises
11084                ? 'if (s && s.then) {\n' +
11085                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
11086                  ' if (!("$$v" in s)) {\n' +
11087                    ' p=s;\n' +
11088                    ' p.$$v = undefined;\n' +
11089                    ' p.then(function(v) {p.$$v=v;});\n' +
11090                    '}\n' +
11091                  ' s=s.$$v\n' +
11092                '}\n'
11093                : '');
11094    });
11095    code += 'return s;';
11096
11097    /* jshint -W054 */
11098    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
11099    /* jshint +W054 */
11100    evaledFnGetter.toString = valueFn(code);
11101    fn = options.unwrapPromises ? function(scope, locals) {
11102      return evaledFnGetter(scope, locals, promiseWarning);
11103    } : evaledFnGetter;
11104  }
11105
11106  // Only cache the value if it's not going to mess up the cache object
11107  // This is more performant that using Object.prototype.hasOwnProperty.call
11108  if (path !== 'hasOwnProperty') {
11109    getterFnCache[path] = fn;
11110  }
11111  return fn;
11112}
11113
11114///////////////////////////////////
11115
11116/**
11117 * @ngdoc service
11118 * @name $parse
11119 * @kind function
11120 *
11121 * @description
11122 *
11123 * Converts Angular {@link guide/expression expression} into a function.
11124 *
11125 * ```js
11126 *   var getter = $parse('user.name');
11127 *   var setter = getter.assign;
11128 *   var context = {user:{name:'angular'}};
11129 *   var locals = {user:{name:'local'}};
11130 *
11131 *   expect(getter(context)).toEqual('angular');
11132 *   setter(context, 'newValue');
11133 *   expect(context.user.name).toEqual('newValue');
11134 *   expect(getter(context, locals)).toEqual('local');
11135 * ```
11136 *
11137 *
11138 * @param {string} expression String expression to compile.
11139 * @returns {function(context, locals)} a function which represents the compiled expression:
11140 *
11141 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11142 *      are evaluated against (typically a scope object).
11143 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11144 *      `context`.
11145 *
11146 *    The returned function also has the following properties:
11147 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
11148 *        literal.
11149 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
11150 *        constant literals.
11151 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
11152 *        set to a function to change its value on the given context.
11153 *
11154 */
11155
11156
11157/**
11158 * @ngdoc provider
11159 * @name $parseProvider
11160 * @kind function
11161 *
11162 * @description
11163 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
11164 *  service.
11165 */
11166function $ParseProvider() {
11167  var cache = {};
11168
11169  var $parseOptions = {
11170    csp: false,
11171    unwrapPromises: false,
11172    logPromiseWarnings: true
11173  };
11174
11175
11176  /**
11177   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11178   *
11179   * @ngdoc method
11180   * @name $parseProvider#unwrapPromises
11181   * @description
11182   *
11183   * **This feature is deprecated, see deprecation notes below for more info**
11184   *
11185   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
11186   * found at any part of the expression. In other words, if set to true, the expression will always
11187   * result in a non-promise value.
11188   *
11189   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
11190   * the fulfillment value is used in place of the promise while evaluating the expression.
11191   *
11192   * **Deprecation notice**
11193   *
11194   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
11195   * dichotomy between data access in templates (accessed as raw values) and controller code
11196   * (accessed as promises).
11197   *
11198   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
11199   * the model access there.
11200   *
11201   * Other downsides of automatic promise unwrapping:
11202   *
11203   * - when building components it's often desirable to receive the raw promises
11204   * - adds complexity and slows down expression evaluation
11205   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
11206   *   generated
11207   * - makes IDE auto-completion and tool support hard
11208   *
11209   * **Warning Logs**
11210   *
11211   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
11212   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
11213   * `$parseProvider.logPromiseWarnings(false)` api.
11214   *
11215   *
11216   * @param {boolean=} value New value.
11217   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11218   *                         setter.
11219   */
11220  this.unwrapPromises = function(value) {
11221    if (isDefined(value)) {
11222      $parseOptions.unwrapPromises = !!value;
11223      return this;
11224    } else {
11225      return $parseOptions.unwrapPromises;
11226    }
11227  };
11228
11229
11230  /**
11231   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11232   *
11233   * @ngdoc method
11234   * @name $parseProvider#logPromiseWarnings
11235   * @description
11236   *
11237   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11238   *
11239   * The default is set to `true`.
11240   *
11241   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11242   *
11243   * @param {boolean=} value New value.
11244   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11245   *                         setter.
11246   */
11247 this.logPromiseWarnings = function(value) {
11248    if (isDefined(value)) {
11249      $parseOptions.logPromiseWarnings = value;
11250      return this;
11251    } else {
11252      return $parseOptions.logPromiseWarnings;
11253    }
11254  };
11255
11256
11257  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
11258    $parseOptions.csp = $sniffer.csp;
11259
11260    promiseWarning = function promiseWarningFn(fullExp) {
11261      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11262      promiseWarningCache[fullExp] = true;
11263      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11264          'Automatic unwrapping of promises in Angular expressions is deprecated.');
11265    };
11266
11267    return function(exp) {
11268      var parsedExpression;
11269
11270      switch (typeof exp) {
11271        case 'string':
11272
11273          if (cache.hasOwnProperty(exp)) {
11274            return cache[exp];
11275          }
11276
11277          var lexer = new Lexer($parseOptions);
11278          var parser = new Parser(lexer, $filter, $parseOptions);
11279          parsedExpression = parser.parse(exp);
11280
11281          if (exp !== 'hasOwnProperty') {
11282            // Only cache the value if it's not going to mess up the cache object
11283            // This is more performant that using Object.prototype.hasOwnProperty.call
11284            cache[exp] = parsedExpression;
11285          }
11286
11287          return parsedExpression;
11288
11289        case 'function':
11290          return exp;
11291
11292        default:
11293          return noop;
11294      }
11295    };
11296  }];
11297}
11298
11299/**
11300 * @ngdoc service
11301 * @name $q
11302 * @requires $rootScope
11303 *
11304 * @description
11305 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
11306 *
11307 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11308 * interface for interacting with an object that represents the result of an action that is
11309 * performed asynchronously, and may or may not be finished at any given point in time.
11310 *
11311 * From the perspective of dealing with error handling, deferred and promise APIs are to
11312 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11313 *
11314 * ```js
11315 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11316 *   // are available in the current lexical scope (they could have been injected or passed in).
11317 *
11318 *   function asyncGreet(name) {
11319 *     var deferred = $q.defer();
11320 *
11321 *     setTimeout(function() {
11322 *       deferred.notify('About to greet ' + name + '.');
11323 *
11324 *       if (okToGreet(name)) {
11325 *         deferred.resolve('Hello, ' + name + '!');
11326 *       } else {
11327 *         deferred.reject('Greeting ' + name + ' is not allowed.');
11328 *       }
11329 *     }, 1000);
11330 *
11331 *     return deferred.promise;
11332 *   }
11333 *
11334 *   var promise = asyncGreet('Robin Hood');
11335 *   promise.then(function(greeting) {
11336 *     alert('Success: ' + greeting);
11337 *   }, function(reason) {
11338 *     alert('Failed: ' + reason);
11339 *   }, function(update) {
11340 *     alert('Got notification: ' + update);
11341 *   });
11342 * ```
11343 *
11344 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11345 * comes in the way of guarantees that promise and deferred APIs make, see
11346 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11347 *
11348 * Additionally the promise api allows for composition that is very hard to do with the
11349 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11350 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11351 * section on serial or parallel joining of promises.
11352 *
11353 *
11354 * # The Deferred API
11355 *
11356 * A new instance of deferred is constructed by calling `$q.defer()`.
11357 *
11358 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11359 * that can be used for signaling the successful or unsuccessful completion, as well as the status
11360 * of the task.
11361 *
11362 * **Methods**
11363 *
11364 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11365 *   constructed via `$q.reject`, the promise will be rejected instead.
11366 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11367 *   resolving it with a rejection constructed via `$q.reject`.
11368 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11369 *   multiple times before the promise is either resolved or rejected.
11370 *
11371 * **Properties**
11372 *
11373 * - promise – `{Promise}` – promise object associated with this deferred.
11374 *
11375 *
11376 * # The Promise API
11377 *
11378 * A new promise instance is created when a deferred instance is created and can be retrieved by
11379 * calling `deferred.promise`.
11380 *
11381 * The purpose of the promise object is to allow for interested parties to get access to the result
11382 * of the deferred task when it completes.
11383 *
11384 * **Methods**
11385 *
11386 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11387 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11388 *   as soon as the result is available. The callbacks are called with a single argument: the result
11389 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11390 *   provide a progress indication, before the promise is resolved or rejected.
11391 *
11392 *   This method *returns a new promise* which is resolved or rejected via the return value of the
11393 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11394 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11395 *   method.
11396 *
11397 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11398 *
11399 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11400 *   but to do so without modifying the final value. This is useful to release resources or do some
11401 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11402 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11403 *   more information.
11404 *
11405 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11406 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11407 *   make your code IE8 and Android 2.x compatible.
11408 *
11409 * # Chaining promises
11410 *
11411 * Because calling the `then` method of a promise returns a new derived promise, it is easily
11412 * possible to create a chain of promises:
11413 *
11414 * ```js
11415 *   promiseB = promiseA.then(function(result) {
11416 *     return result + 1;
11417 *   });
11418 *
11419 *   // promiseB will be resolved immediately after promiseA is resolved and its value
11420 *   // will be the result of promiseA incremented by 1
11421 * ```
11422 *
11423 * It is possible to create chains of any length and since a promise can be resolved with another
11424 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11425 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11426 * $http's response interceptors.
11427 *
11428 *
11429 * # Differences between Kris Kowal's Q and $q
11430 *
11431 *  There are two main differences:
11432 *
11433 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11434 *   mechanism in angular, which means faster propagation of resolution or rejection into your
11435 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11436 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11437 *   all the important functionality needed for common async tasks.
11438 *
11439 *  # Testing
11440 *
11441 *  ```js
11442 *    it('should simulate promise', inject(function($q, $rootScope) {
11443 *      var deferred = $q.defer();
11444 *      var promise = deferred.promise;
11445 *      var resolvedValue;
11446 *
11447 *      promise.then(function(value) { resolvedValue = value; });
11448 *      expect(resolvedValue).toBeUndefined();
11449 *
11450 *      // Simulate resolving of promise
11451 *      deferred.resolve(123);
11452 *      // Note that the 'then' function does not get called synchronously.
11453 *      // This is because we want the promise API to always be async, whether or not
11454 *      // it got called synchronously or asynchronously.
11455 *      expect(resolvedValue).toBeUndefined();
11456 *
11457 *      // Propagate promise resolution to 'then' functions using $apply().
11458 *      $rootScope.$apply();
11459 *      expect(resolvedValue).toEqual(123);
11460 *    }));
11461 *  ```
11462 */
11463function $QProvider() {
11464
11465  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
11466    return qFactory(function(callback) {
11467      $rootScope.$evalAsync(callback);
11468    }, $exceptionHandler);
11469  }];
11470}
11471
11472
11473/**
11474 * Constructs a promise manager.
11475 *
11476 * @param {function(Function)} nextTick Function for executing functions in the next turn.
11477 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11478 *     debugging purposes.
11479 * @returns {object} Promise manager.
11480 */
11481function qFactory(nextTick, exceptionHandler) {
11482
11483  /**
11484   * @ngdoc method
11485   * @name $q#defer
11486   * @kind function
11487   *
11488   * @description
11489   * Creates a `Deferred` object which represents a task which will finish in the future.
11490   *
11491   * @returns {Deferred} Returns a new instance of deferred.
11492   */
11493  var defer = function() {
11494    var pending = [],
11495        value, deferred;
11496
11497    deferred = {
11498
11499      resolve: function(val) {
11500        if (pending) {
11501          var callbacks = pending;
11502          pending = undefined;
11503          value = ref(val);
11504
11505          if (callbacks.length) {
11506            nextTick(function() {
11507              var callback;
11508              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11509                callback = callbacks[i];
11510                value.then(callback[0], callback[1], callback[2]);
11511              }
11512            });
11513          }
11514        }
11515      },
11516
11517
11518      reject: function(reason) {
11519        deferred.resolve(createInternalRejectedPromise(reason));
11520      },
11521
11522
11523      notify: function(progress) {
11524        if (pending) {
11525          var callbacks = pending;
11526
11527          if (pending.length) {
11528            nextTick(function() {
11529              var callback;
11530              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11531                callback = callbacks[i];
11532                callback[2](progress);
11533              }
11534            });
11535          }
11536        }
11537      },
11538
11539
11540      promise: {
11541        then: function(callback, errback, progressback) {
11542          var result = defer();
11543
11544          var wrappedCallback = function(value) {
11545            try {
11546              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11547            } catch(e) {
11548              result.reject(e);
11549              exceptionHandler(e);
11550            }
11551          };
11552
11553          var wrappedErrback = function(reason) {
11554            try {
11555              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11556            } catch(e) {
11557              result.reject(e);
11558              exceptionHandler(e);
11559            }
11560          };
11561
11562          var wrappedProgressback = function(progress) {
11563            try {
11564              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11565            } catch(e) {
11566              exceptionHandler(e);
11567            }
11568          };
11569
11570          if (pending) {
11571            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11572          } else {
11573            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11574          }
11575
11576          return result.promise;
11577        },
11578
11579        "catch": function(callback) {
11580          return this.then(null, callback);
11581        },
11582
11583        "finally": function(callback) {
11584
11585          function makePromise(value, resolved) {
11586            var result = defer();
11587            if (resolved) {
11588              result.resolve(value);
11589            } else {
11590              result.reject(value);
11591            }
11592            return result.promise;
11593          }
11594
11595          function handleCallback(value, isResolved) {
11596            var callbackOutput = null;
11597            try {
11598              callbackOutput = (callback ||defaultCallback)();
11599            } catch(e) {
11600              return makePromise(e, false);
11601            }
11602            if (isPromiseLike(callbackOutput)) {
11603              return callbackOutput.then(function() {
11604                return makePromise(value, isResolved);
11605              }, function(error) {
11606                return makePromise(error, false);
11607              });
11608            } else {
11609              return makePromise(value, isResolved);
11610            }
11611          }
11612
11613          return this.then(function(value) {
11614            return handleCallback(value, true);
11615          }, function(error) {
11616            return handleCallback(error, false);
11617          });
11618        }
11619      }
11620    };
11621
11622    return deferred;
11623  };
11624
11625
11626  var ref = function(value) {
11627    if (isPromiseLike(value)) return value;
11628    return {
11629      then: function(callback) {
11630        var result = defer();
11631        nextTick(function() {
11632          result.resolve(callback(value));
11633        });
11634        return result.promise;
11635      }
11636    };
11637  };
11638
11639
11640  /**
11641   * @ngdoc method
11642   * @name $q#reject
11643   * @kind function
11644   *
11645   * @description
11646   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11647   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11648   * a promise chain, you don't need to worry about it.
11649   *
11650   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11651   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11652   * a promise error callback and you want to forward the error to the promise derived from the
11653   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11654   * `reject`.
11655   *
11656   * ```js
11657   *   promiseB = promiseA.then(function(result) {
11658   *     // success: do something and resolve promiseB
11659   *     //          with the old or a new result
11660   *     return result;
11661   *   }, function(reason) {
11662   *     // error: handle the error if possible and
11663   *     //        resolve promiseB with newPromiseOrValue,
11664   *     //        otherwise forward the rejection to promiseB
11665   *     if (canHandle(reason)) {
11666   *      // handle the error and recover
11667   *      return newPromiseOrValue;
11668   *     }
11669   *     return $q.reject(reason);
11670   *   });
11671   * ```
11672   *
11673   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11674   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11675   */
11676  var reject = function(reason) {
11677    var result = defer();
11678    result.reject(reason);
11679    return result.promise;
11680  };
11681
11682  var createInternalRejectedPromise = function(reason) {
11683    return {
11684      then: function(callback, errback) {
11685        var result = defer();
11686        nextTick(function() {
11687          try {
11688            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11689          } catch(e) {
11690            result.reject(e);
11691            exceptionHandler(e);
11692          }
11693        });
11694        return result.promise;
11695      }
11696    };
11697  };
11698
11699
11700  /**
11701   * @ngdoc method
11702   * @name $q#when
11703   * @kind function
11704   *
11705   * @description
11706   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11707   * This is useful when you are dealing with an object that might or might not be a promise, or if
11708   * the promise comes from a source that can't be trusted.
11709   *
11710   * @param {*} value Value or a promise
11711   * @returns {Promise} Returns a promise of the passed value or promise
11712   */
11713  var when = function(value, callback, errback, progressback) {
11714    var result = defer(),
11715        done;
11716
11717    var wrappedCallback = function(value) {
11718      try {
11719        return (isFunction(callback) ? callback : defaultCallback)(value);
11720      } catch (e) {
11721        exceptionHandler(e);
11722        return reject(e);
11723      }
11724    };
11725
11726    var wrappedErrback = function(reason) {
11727      try {
11728        return (isFunction(errback) ? errback : defaultErrback)(reason);
11729      } catch (e) {
11730        exceptionHandler(e);
11731        return reject(e);
11732      }
11733    };
11734
11735    var wrappedProgressback = function(progress) {
11736      try {
11737        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11738      } catch (e) {
11739        exceptionHandler(e);
11740      }
11741    };
11742
11743    nextTick(function() {
11744      ref(value).then(function(value) {
11745        if (done) return;
11746        done = true;
11747        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11748      }, function(reason) {
11749        if (done) return;
11750        done = true;
11751        result.resolve(wrappedErrback(reason));
11752      }, function(progress) {
11753        if (done) return;
11754        result.notify(wrappedProgressback(progress));
11755      });
11756    });
11757
11758    return result.promise;
11759  };
11760
11761
11762  function defaultCallback(value) {
11763    return value;
11764  }
11765
11766
11767  function defaultErrback(reason) {
11768    return reject(reason);
11769  }
11770
11771
11772  /**
11773   * @ngdoc method
11774   * @name $q#all
11775   * @kind function
11776   *
11777   * @description
11778   * Combines multiple promises into a single promise that is resolved when all of the input
11779   * promises are resolved.
11780   *
11781   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11782   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11783   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11784   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11785   *   with the same rejection value.
11786   */
11787  function all(promises) {
11788    var deferred = defer(),
11789        counter = 0,
11790        results = isArray(promises) ? [] : {};
11791
11792    forEach(promises, function(promise, key) {
11793      counter++;
11794      ref(promise).then(function(value) {
11795        if (results.hasOwnProperty(key)) return;
11796        results[key] = value;
11797        if (!(--counter)) deferred.resolve(results);
11798      }, function(reason) {
11799        if (results.hasOwnProperty(key)) return;
11800        deferred.reject(reason);
11801      });
11802    });
11803
11804    if (counter === 0) {
11805      deferred.resolve(results);
11806    }
11807
11808    return deferred.promise;
11809  }
11810
11811  return {
11812    defer: defer,
11813    reject: reject,
11814    when: when,
11815    all: all
11816  };
11817}
11818
11819function $$RAFProvider(){ //rAF
11820  this.$get = ['$window', '$timeout', function($window, $timeout) {
11821    var requestAnimationFrame = $window.requestAnimationFrame ||
11822                                $window.webkitRequestAnimationFrame ||
11823                                $window.mozRequestAnimationFrame;
11824
11825    var cancelAnimationFrame = $window.cancelAnimationFrame ||
11826                               $window.webkitCancelAnimationFrame ||
11827                               $window.mozCancelAnimationFrame ||
11828                               $window.webkitCancelRequestAnimationFrame;
11829
11830    var rafSupported = !!requestAnimationFrame;
11831    var raf = rafSupported
11832      ? function(fn) {
11833          var id = requestAnimationFrame(fn);
11834          return function() {
11835            cancelAnimationFrame(id);
11836          };
11837        }
11838      : function(fn) {
11839          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
11840          return function() {
11841            $timeout.cancel(timer);
11842          };
11843        };
11844
11845    raf.supported = rafSupported;
11846
11847    return raf;
11848  }];
11849}
11850
11851/**
11852 * DESIGN NOTES
11853 *
11854 * The design decisions behind the scope are heavily favored for speed and memory consumption.
11855 *
11856 * The typical use of scope is to watch the expressions, which most of the time return the same
11857 * value as last time so we optimize the operation.
11858 *
11859 * Closures construction is expensive in terms of speed as well as memory:
11860 *   - No closures, instead use prototypical inheritance for API
11861 *   - Internal state needs to be stored on scope directly, which means that private state is
11862 *     exposed as $$____ properties
11863 *
11864 * Loop operations are optimized by using while(count--) { ... }
11865 *   - this means that in order to keep the same order of execution as addition we have to add
11866 *     items to the array at the beginning (unshift) instead of at the end (push)
11867 *
11868 * Child scopes are created and removed often
11869 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11870 *
11871 * There are few watches then a lot of observers. This is why you don't want the observer to be
11872 * implemented in the same way as watch. Watch requires return of initialization function which
11873 * are expensive to construct.
11874 */
11875
11876
11877/**
11878 * @ngdoc provider
11879 * @name $rootScopeProvider
11880 * @description
11881 *
11882 * Provider for the $rootScope service.
11883 */
11884
11885/**
11886 * @ngdoc method
11887 * @name $rootScopeProvider#digestTtl
11888 * @description
11889 *
11890 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11891 * assuming that the model is unstable.
11892 *
11893 * The current default is 10 iterations.
11894 *
11895 * In complex applications it's possible that the dependencies between `$watch`s will result in
11896 * several digest iterations. However if an application needs more than the default 10 digest
11897 * iterations for its model to stabilize then you should investigate what is causing the model to
11898 * continuously change during the digest.
11899 *
11900 * Increasing the TTL could have performance implications, so you should not change it without
11901 * proper justification.
11902 *
11903 * @param {number} limit The number of digest iterations.
11904 */
11905
11906
11907/**
11908 * @ngdoc service
11909 * @name $rootScope
11910 * @description
11911 *
11912 * Every application has a single root {@link ng.$rootScope.Scope scope}.
11913 * All other scopes are descendant scopes of the root scope. Scopes provide separation
11914 * between the model and the view, via a mechanism for watching the model for changes.
11915 * They also provide an event emission/broadcast and subscription facility. See the
11916 * {@link guide/scope developer guide on scopes}.
11917 */
11918function $RootScopeProvider(){
11919  var TTL = 10;
11920  var $rootScopeMinErr = minErr('$rootScope');
11921  var lastDirtyWatch = null;
11922
11923  this.digestTtl = function(value) {
11924    if (arguments.length) {
11925      TTL = value;
11926    }
11927    return TTL;
11928  };
11929
11930  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11931      function( $injector,   $exceptionHandler,   $parse,   $browser) {
11932
11933    /**
11934     * @ngdoc type
11935     * @name $rootScope.Scope
11936     *
11937     * @description
11938     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11939     * {@link auto.$injector $injector}. Child scopes are created using the
11940     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
11941     * compiled HTML template is executed.)
11942     *
11943     * Here is a simple scope snippet to show how you can interact with the scope.
11944     * ```html
11945     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11946     * ```
11947     *
11948     * # Inheritance
11949     * A scope can inherit from a parent scope, as in this example:
11950     * ```js
11951         var parent = $rootScope;
11952         var child = parent.$new();
11953
11954         parent.salutation = "Hello";
11955         child.name = "World";
11956         expect(child.salutation).toEqual('Hello');
11957
11958         child.salutation = "Welcome";
11959         expect(child.salutation).toEqual('Welcome');
11960         expect(parent.salutation).toEqual('Hello');
11961     * ```
11962     *
11963     *
11964     * @param {Object.<string, function()>=} providers Map of service factory which need to be
11965     *                                       provided for the current scope. Defaults to {@link ng}.
11966     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11967     *                              append/override services provided by `providers`. This is handy
11968     *                              when unit-testing and having the need to override a default
11969     *                              service.
11970     * @returns {Object} Newly created scope.
11971     *
11972     */
11973    function Scope() {
11974      this.$id = nextUid();
11975      this.$$phase = this.$parent = this.$$watchers =
11976                     this.$$nextSibling = this.$$prevSibling =
11977                     this.$$childHead = this.$$childTail = null;
11978      this['this'] = this.$root =  this;
11979      this.$$destroyed = false;
11980      this.$$asyncQueue = [];
11981      this.$$postDigestQueue = [];
11982      this.$$listeners = {};
11983      this.$$listenerCount = {};
11984      this.$$isolateBindings = {};
11985    }
11986
11987    /**
11988     * @ngdoc property
11989     * @name $rootScope.Scope#$id
11990     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11991     *   debugging.
11992     */
11993
11994
11995    Scope.prototype = {
11996      constructor: Scope,
11997      /**
11998       * @ngdoc method
11999       * @name $rootScope.Scope#$new
12000       * @kind function
12001       *
12002       * @description
12003       * Creates a new child {@link ng.$rootScope.Scope scope}.
12004       *
12005       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
12006       * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
12007       * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
12008       *
12009       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
12010       * desired for the scope and its child scopes to be permanently detached from the parent and
12011       * thus stop participating in model change detection and listener notification by invoking.
12012       *
12013       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
12014       *         parent scope. The scope is isolated, as it can not see parent scope properties.
12015       *         When creating widgets, it is useful for the widget to not accidentally read parent
12016       *         state.
12017       *
12018       * @returns {Object} The newly created child scope.
12019       *
12020       */
12021      $new: function(isolate) {
12022        var ChildScope,
12023            child;
12024
12025        if (isolate) {
12026          child = new Scope();
12027          child.$root = this.$root;
12028          // ensure that there is just one async queue per $rootScope and its children
12029          child.$$asyncQueue = this.$$asyncQueue;
12030          child.$$postDigestQueue = this.$$postDigestQueue;
12031        } else {
12032          // Only create a child scope class if somebody asks for one,
12033          // but cache it to allow the VM to optimize lookups.
12034          if (!this.$$childScopeClass) {
12035            this.$$childScopeClass = function() {
12036              this.$$watchers = this.$$nextSibling =
12037                  this.$$childHead = this.$$childTail = null;
12038              this.$$listeners = {};
12039              this.$$listenerCount = {};
12040              this.$id = nextUid();
12041              this.$$childScopeClass = null;
12042            };
12043            this.$$childScopeClass.prototype = this;
12044          }
12045          child = new this.$$childScopeClass();
12046        }
12047        child['this'] = child;
12048        child.$parent = this;
12049        child.$$prevSibling = this.$$childTail;
12050        if (this.$$childHead) {
12051          this.$$childTail.$$nextSibling = child;
12052          this.$$childTail = child;
12053        } else {
12054          this.$$childHead = this.$$childTail = child;
12055        }
12056        return child;
12057      },
12058
12059      /**
12060       * @ngdoc method
12061       * @name $rootScope.Scope#$watch
12062       * @kind function
12063       *
12064       * @description
12065       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
12066       *
12067       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
12068       *   $digest()} and should return the value that will be watched. (Since
12069       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
12070       *   `watchExpression` can execute multiple times per
12071       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
12072       * - The `listener` is called only when the value from the current `watchExpression` and the
12073       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
12074       *   see below). Inequality is determined according to reference inequality,
12075       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
12076       *    via the `!==` Javascript operator, unless `objectEquality == true`
12077       *   (see next point)
12078       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
12079       *   according to the {@link angular.equals} function. To save the value of the object for
12080       *   later comparison, the {@link angular.copy} function is used. This therefore means that
12081       *   watching complex objects will have adverse memory and performance implications.
12082       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
12083       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
12084       *   iteration limit is 10 to prevent an infinite loop deadlock.
12085       *
12086       *
12087       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
12088       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
12089       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
12090       * change is detected, be prepared for multiple calls to your listener.)
12091       *
12092       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
12093       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
12094       * watcher. In rare cases, this is undesirable because the listener is called when the result
12095       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
12096       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
12097       * listener was called due to initialization.
12098       *
12099       * The example below contains an illustration of using a function as your $watch listener
12100       *
12101       *
12102       * # Example
12103       * ```js
12104           // let's assume that scope was dependency injected as the $rootScope
12105           var scope = $rootScope;
12106           scope.name = 'misko';
12107           scope.counter = 0;
12108
12109           expect(scope.counter).toEqual(0);
12110           scope.$watch('name', function(newValue, oldValue) {
12111             scope.counter = scope.counter + 1;
12112           });
12113           expect(scope.counter).toEqual(0);
12114
12115           scope.$digest();
12116           // the listener is always called during the first $digest loop after it was registered
12117           expect(scope.counter).toEqual(1);
12118
12119           scope.$digest();
12120           // but now it will not be called unless the value changes
12121           expect(scope.counter).toEqual(1);
12122
12123           scope.name = 'adam';
12124           scope.$digest();
12125           expect(scope.counter).toEqual(2);
12126
12127
12128
12129           // Using a listener function
12130           var food;
12131           scope.foodCounter = 0;
12132           expect(scope.foodCounter).toEqual(0);
12133           scope.$watch(
12134             // This is the listener function
12135             function() { return food; },
12136             // This is the change handler
12137             function(newValue, oldValue) {
12138               if ( newValue !== oldValue ) {
12139                 // Only increment the counter if the value changed
12140                 scope.foodCounter = scope.foodCounter + 1;
12141               }
12142             }
12143           );
12144           // No digest has been run so the counter will be zero
12145           expect(scope.foodCounter).toEqual(0);
12146
12147           // Run the digest but since food has not changed count will still be zero
12148           scope.$digest();
12149           expect(scope.foodCounter).toEqual(0);
12150
12151           // Update food and run digest.  Now the counter will increment
12152           food = 'cheeseburger';
12153           scope.$digest();
12154           expect(scope.foodCounter).toEqual(1);
12155
12156       * ```
12157       *
12158       *
12159       *
12160       * @param {(function()|string)} watchExpression Expression that is evaluated on each
12161       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
12162       *    a call to the `listener`.
12163       *
12164       *    - `string`: Evaluated as {@link guide/expression expression}
12165       *    - `function(scope)`: called with current `scope` as a parameter.
12166       * @param {(function()|string)=} listener Callback called whenever the return value of
12167       *   the `watchExpression` changes.
12168       *
12169       *    - `string`: Evaluated as {@link guide/expression expression}
12170       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
12171       *      parameters.
12172       *
12173       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
12174       *     comparing for reference equality.
12175       * @returns {function()} Returns a deregistration function for this listener.
12176       */
12177      $watch: function(watchExp, listener, objectEquality) {
12178        var scope = this,
12179            get = compileToFn(watchExp, 'watch'),
12180            array = scope.$$watchers,
12181            watcher = {
12182              fn: listener,
12183              last: initWatchVal,
12184              get: get,
12185              exp: watchExp,
12186              eq: !!objectEquality
12187            };
12188
12189        lastDirtyWatch = null;
12190
12191        // in the case user pass string, we need to compile it, do we really need this ?
12192        if (!isFunction(listener)) {
12193          var listenFn = compileToFn(listener || noop, 'listener');
12194          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
12195        }
12196
12197        if (typeof watchExp == 'string' && get.constant) {
12198          var originalFn = watcher.fn;
12199          watcher.fn = function(newVal, oldVal, scope) {
12200            originalFn.call(this, newVal, oldVal, scope);
12201            arrayRemove(array, watcher);
12202          };
12203        }
12204
12205        if (!array) {
12206          array = scope.$$watchers = [];
12207        }
12208        // we use unshift since we use a while loop in $digest for speed.
12209        // the while loop reads in reverse order.
12210        array.unshift(watcher);
12211
12212        return function deregisterWatch() {
12213          arrayRemove(array, watcher);
12214          lastDirtyWatch = null;
12215        };
12216      },
12217
12218
12219      /**
12220       * @ngdoc method
12221       * @name $rootScope.Scope#$watchCollection
12222       * @kind function
12223       *
12224       * @description
12225       * Shallow watches the properties of an object and fires whenever any of the properties change
12226       * (for arrays, this implies watching the array items; for object maps, this implies watching
12227       * the properties). If a change is detected, the `listener` callback is fired.
12228       *
12229       * - The `obj` collection is observed via standard $watch operation and is examined on every
12230       *   call to $digest() to see if any items have been added, removed, or moved.
12231       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
12232       *   adding, removing, and moving items belonging to an object or array.
12233       *
12234       *
12235       * # Example
12236       * ```js
12237          $scope.names = ['igor', 'matias', 'misko', 'james'];
12238          $scope.dataCount = 4;
12239
12240          $scope.$watchCollection('names', function(newNames, oldNames) {
12241            $scope.dataCount = newNames.length;
12242          });
12243
12244          expect($scope.dataCount).toEqual(4);
12245          $scope.$digest();
12246
12247          //still at 4 ... no changes
12248          expect($scope.dataCount).toEqual(4);
12249
12250          $scope.names.pop();
12251          $scope.$digest();
12252
12253          //now there's been a change
12254          expect($scope.dataCount).toEqual(3);
12255       * ```
12256       *
12257       *
12258       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12259       *    expression value should evaluate to an object or an array which is observed on each
12260       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12261       *    collection will trigger a call to the `listener`.
12262       *
12263       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12264       *    when a change is detected.
12265       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12266       *    - The `oldCollection` object is a copy of the former collection data.
12267       *      Due to performance considerations, the`oldCollection` value is computed only if the
12268       *      `listener` function declares two or more arguments.
12269       *    - The `scope` argument refers to the current scope.
12270       *
12271       * @returns {function()} Returns a de-registration function for this listener. When the
12272       *    de-registration function is executed, the internal watch operation is terminated.
12273       */
12274      $watchCollection: function(obj, listener) {
12275        var self = this;
12276        // the current value, updated on each dirty-check run
12277        var newValue;
12278        // a shallow copy of the newValue from the last dirty-check run,
12279        // updated to match newValue during dirty-check run
12280        var oldValue;
12281        // a shallow copy of the newValue from when the last change happened
12282        var veryOldValue;
12283        // only track veryOldValue if the listener is asking for it
12284        var trackVeryOldValue = (listener.length > 1);
12285        var changeDetected = 0;
12286        var objGetter = $parse(obj);
12287        var internalArray = [];
12288        var internalObject = {};
12289        var initRun = true;
12290        var oldLength = 0;
12291
12292        function $watchCollectionWatch() {
12293          newValue = objGetter(self);
12294          var newLength, key, bothNaN;
12295
12296          if (!isObject(newValue)) { // if primitive
12297            if (oldValue !== newValue) {
12298              oldValue = newValue;
12299              changeDetected++;
12300            }
12301          } else if (isArrayLike(newValue)) {
12302            if (oldValue !== internalArray) {
12303              // we are transitioning from something which was not an array into array.
12304              oldValue = internalArray;
12305              oldLength = oldValue.length = 0;
12306              changeDetected++;
12307            }
12308
12309            newLength = newValue.length;
12310
12311            if (oldLength !== newLength) {
12312              // if lengths do not match we need to trigger change notification
12313              changeDetected++;
12314              oldValue.length = oldLength = newLength;
12315            }
12316            // copy the items to oldValue and look for changes.
12317            for (var i = 0; i < newLength; i++) {
12318              bothNaN = (oldValue[i] !== oldValue[i]) &&
12319                  (newValue[i] !== newValue[i]);
12320              if (!bothNaN && (oldValue[i] !== newValue[i])) {
12321                changeDetected++;
12322                oldValue[i] = newValue[i];
12323              }
12324            }
12325          } else {
12326            if (oldValue !== internalObject) {
12327              // we are transitioning from something which was not an object into object.
12328              oldValue = internalObject = {};
12329              oldLength = 0;
12330              changeDetected++;
12331            }
12332            // copy the items to oldValue and look for changes.
12333            newLength = 0;
12334            for (key in newValue) {
12335              if (newValue.hasOwnProperty(key)) {
12336                newLength++;
12337                if (oldValue.hasOwnProperty(key)) {
12338                  bothNaN = (oldValue[key] !== oldValue[key]) &&
12339                      (newValue[key] !== newValue[key]);
12340                  if (!bothNaN && (oldValue[key] !== newValue[key])) {
12341                    changeDetected++;
12342                    oldValue[key] = newValue[key];
12343                  }
12344                } else {
12345                  oldLength++;
12346                  oldValue[key] = newValue[key];
12347                  changeDetected++;
12348                }
12349              }
12350            }
12351            if (oldLength > newLength) {
12352              // we used to have more keys, need to find them and destroy them.
12353              changeDetected++;
12354              for(key in oldValue) {
12355                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12356                  oldLength--;
12357                  delete oldValue[key];
12358                }
12359              }
12360            }
12361          }
12362          return changeDetected;
12363        }
12364
12365        function $watchCollectionAction() {
12366          if (initRun) {
12367            initRun = false;
12368            listener(newValue, newValue, self);
12369          } else {
12370            listener(newValue, veryOldValue, self);
12371          }
12372
12373          // make a copy for the next time a collection is changed
12374          if (trackVeryOldValue) {
12375            if (!isObject(newValue)) {
12376              //primitive
12377              veryOldValue = newValue;
12378            } else if (isArrayLike(newValue)) {
12379              veryOldValue = new Array(newValue.length);
12380              for (var i = 0; i < newValue.length; i++) {
12381                veryOldValue[i] = newValue[i];
12382              }
12383            } else { // if object
12384              veryOldValue = {};
12385              for (var key in newValue) {
12386                if (hasOwnProperty.call(newValue, key)) {
12387                  veryOldValue[key] = newValue[key];
12388                }
12389              }
12390            }
12391          }
12392        }
12393
12394        return this.$watch($watchCollectionWatch, $watchCollectionAction);
12395      },
12396
12397      /**
12398       * @ngdoc method
12399       * @name $rootScope.Scope#$digest
12400       * @kind function
12401       *
12402       * @description
12403       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12404       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12405       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12406       * until no more listeners are firing. This means that it is possible to get into an infinite
12407       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12408       * iterations exceeds 10.
12409       *
12410       * Usually, you don't call `$digest()` directly in
12411       * {@link ng.directive:ngController controllers} or in
12412       * {@link ng.$compileProvider#directive directives}.
12413       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12414       * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12415       *
12416       * If you want to be notified whenever `$digest()` is called,
12417       * you can register a `watchExpression` function with
12418       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12419       *
12420       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12421       *
12422       * # Example
12423       * ```js
12424           var scope = ...;
12425           scope.name = 'misko';
12426           scope.counter = 0;
12427
12428           expect(scope.counter).toEqual(0);
12429           scope.$watch('name', function(newValue, oldValue) {
12430             scope.counter = scope.counter + 1;
12431           });
12432           expect(scope.counter).toEqual(0);
12433
12434           scope.$digest();
12435           // the listener is always called during the first $digest loop after it was registered
12436           expect(scope.counter).toEqual(1);
12437
12438           scope.$digest();
12439           // but now it will not be called unless the value changes
12440           expect(scope.counter).toEqual(1);
12441
12442           scope.name = 'adam';
12443           scope.$digest();
12444           expect(scope.counter).toEqual(2);
12445       * ```
12446       *
12447       */
12448      $digest: function() {
12449        var watch, value, last,
12450            watchers,
12451            asyncQueue = this.$$asyncQueue,
12452            postDigestQueue = this.$$postDigestQueue,
12453            length,
12454            dirty, ttl = TTL,
12455            next, current, target = this,
12456            watchLog = [],
12457            logIdx, logMsg, asyncTask;
12458
12459        beginPhase('$digest');
12460
12461        lastDirtyWatch = null;
12462
12463        do { // "while dirty" loop
12464          dirty = false;
12465          current = target;
12466
12467          while(asyncQueue.length) {
12468            try {
12469              asyncTask = asyncQueue.shift();
12470              asyncTask.scope.$eval(asyncTask.expression);
12471            } catch (e) {
12472              clearPhase();
12473              $exceptionHandler(e);
12474            }
12475            lastDirtyWatch = null;
12476          }
12477
12478          traverseScopesLoop:
12479          do { // "traverse the scopes" loop
12480            if ((watchers = current.$$watchers)) {
12481              // process our watches
12482              length = watchers.length;
12483              while (length--) {
12484                try {
12485                  watch = watchers[length];
12486                  // Most common watches are on primitives, in which case we can short
12487                  // circuit it with === operator, only when === fails do we use .equals
12488                  if (watch) {
12489                    if ((value = watch.get(current)) !== (last = watch.last) &&
12490                        !(watch.eq
12491                            ? equals(value, last)
12492                            : (typeof value === 'number' && typeof last === 'number'
12493                               && isNaN(value) && isNaN(last)))) {
12494                      dirty = true;
12495                      lastDirtyWatch = watch;
12496                      watch.last = watch.eq ? copy(value, null) : value;
12497                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
12498                      if (ttl < 5) {
12499                        logIdx = 4 - ttl;
12500                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
12501                        logMsg = (isFunction(watch.exp))
12502                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12503                            : watch.exp;
12504                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12505                        watchLog[logIdx].push(logMsg);
12506                      }
12507                    } else if (watch === lastDirtyWatch) {
12508                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12509                      // have already been tested.
12510                      dirty = false;
12511                      break traverseScopesLoop;
12512                    }
12513                  }
12514                } catch (e) {
12515                  clearPhase();
12516                  $exceptionHandler(e);
12517                }
12518              }
12519            }
12520
12521            // Insanity Warning: scope depth-first traversal
12522            // yes, this code is a bit crazy, but it works and we have tests to prove it!
12523            // this piece should be kept in sync with the traversal in $broadcast
12524            if (!(next = (current.$$childHead ||
12525                (current !== target && current.$$nextSibling)))) {
12526              while(current !== target && !(next = current.$$nextSibling)) {
12527                current = current.$parent;
12528              }
12529            }
12530          } while ((current = next));
12531
12532          // `break traverseScopesLoop;` takes us to here
12533
12534          if((dirty || asyncQueue.length) && !(ttl--)) {
12535            clearPhase();
12536            throw $rootScopeMinErr('infdig',
12537                '{0} $digest() iterations reached. Aborting!\n' +
12538                'Watchers fired in the last 5 iterations: {1}',
12539                TTL, toJson(watchLog));
12540          }
12541
12542        } while (dirty || asyncQueue.length);
12543
12544        clearPhase();
12545
12546        while(postDigestQueue.length) {
12547          try {
12548            postDigestQueue.shift()();
12549          } catch (e) {
12550            $exceptionHandler(e);
12551          }
12552        }
12553      },
12554
12555
12556      /**
12557       * @ngdoc event
12558       * @name $rootScope.Scope#$destroy
12559       * @eventType broadcast on scope being destroyed
12560       *
12561       * @description
12562       * Broadcasted when a scope and its children are being destroyed.
12563       *
12564       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12565       * clean up DOM bindings before an element is removed from the DOM.
12566       */
12567
12568      /**
12569       * @ngdoc method
12570       * @name $rootScope.Scope#$destroy
12571       * @kind function
12572       *
12573       * @description
12574       * Removes the current scope (and all of its children) from the parent scope. Removal implies
12575       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12576       * propagate to the current scope and its children. Removal also implies that the current
12577       * scope is eligible for garbage collection.
12578       *
12579       * The `$destroy()` is usually used by directives such as
12580       * {@link ng.directive:ngRepeat ngRepeat} for managing the
12581       * unrolling of the loop.
12582       *
12583       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12584       * Application code can register a `$destroy` event handler that will give it a chance to
12585       * perform any necessary cleanup.
12586       *
12587       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12588       * clean up DOM bindings before an element is removed from the DOM.
12589       */
12590      $destroy: function() {
12591        // we can't destroy the root scope or a scope that has been already destroyed
12592        if (this.$$destroyed) return;
12593        var parent = this.$parent;
12594
12595        this.$broadcast('$destroy');
12596        this.$$destroyed = true;
12597        if (this === $rootScope) return;
12598
12599        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12600
12601        // sever all the references to parent scopes (after this cleanup, the current scope should
12602        // not be retained by any of our references and should be eligible for garbage collection)
12603        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12604        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12605        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12606        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12607
12608
12609        // All of the code below is bogus code that works around V8's memory leak via optimized code
12610        // and inline caches.
12611        //
12612        // see:
12613        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12614        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12615        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12616
12617        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12618            this.$$childTail = this.$root = null;
12619
12620        // don't reset these to null in case some async task tries to register a listener/watch/task
12621        this.$$listeners = {};
12622        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12623
12624        // prevent NPEs since these methods have references to properties we nulled out
12625        this.$destroy = this.$digest = this.$apply = noop;
12626        this.$on = this.$watch = function() { return noop; };
12627      },
12628
12629      /**
12630       * @ngdoc method
12631       * @name $rootScope.Scope#$eval
12632       * @kind function
12633       *
12634       * @description
12635       * Executes the `expression` on the current scope and returns the result. Any exceptions in
12636       * the expression are propagated (uncaught). This is useful when evaluating Angular
12637       * expressions.
12638       *
12639       * # Example
12640       * ```js
12641           var scope = ng.$rootScope.Scope();
12642           scope.a = 1;
12643           scope.b = 2;
12644
12645           expect(scope.$eval('a+b')).toEqual(3);
12646           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12647       * ```
12648       *
12649       * @param {(string|function())=} expression An angular expression to be executed.
12650       *
12651       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12652       *    - `function(scope)`: execute the function with the current `scope` parameter.
12653       *
12654       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12655       * @returns {*} The result of evaluating the expression.
12656       */
12657      $eval: function(expr, locals) {
12658        return $parse(expr)(this, locals);
12659      },
12660
12661      /**
12662       * @ngdoc method
12663       * @name $rootScope.Scope#$evalAsync
12664       * @kind function
12665       *
12666       * @description
12667       * Executes the expression on the current scope at a later point in time.
12668       *
12669       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12670       * that:
12671       *
12672       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12673       *     rendering).
12674       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12675       *     `expression` execution.
12676       *
12677       * Any exceptions from the execution of the expression are forwarded to the
12678       * {@link ng.$exceptionHandler $exceptionHandler} service.
12679       *
12680       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12681       * will be scheduled. However, it is encouraged to always call code that changes the model
12682       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12683       *
12684       * @param {(string|function())=} expression An angular expression to be executed.
12685       *
12686       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12687       *    - `function(scope)`: execute the function with the current `scope` parameter.
12688       *
12689       */
12690      $evalAsync: function(expr) {
12691        // if we are outside of an $digest loop and this is the first time we are scheduling async
12692        // task also schedule async auto-flush
12693        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12694          $browser.defer(function() {
12695            if ($rootScope.$$asyncQueue.length) {
12696              $rootScope.$digest();
12697            }
12698          });
12699        }
12700
12701        this.$$asyncQueue.push({scope: this, expression: expr});
12702      },
12703
12704      $$postDigest : function(fn) {
12705        this.$$postDigestQueue.push(fn);
12706      },
12707
12708      /**
12709       * @ngdoc method
12710       * @name $rootScope.Scope#$apply
12711       * @kind function
12712       *
12713       * @description
12714       * `$apply()` is used to execute an expression in angular from outside of the angular
12715       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12716       * Because we are calling into the angular framework we need to perform proper scope life
12717       * cycle of {@link ng.$exceptionHandler exception handling},
12718       * {@link ng.$rootScope.Scope#$digest executing watches}.
12719       *
12720       * ## Life cycle
12721       *
12722       * # Pseudo-Code of `$apply()`
12723       * ```js
12724           function $apply(expr) {
12725             try {
12726               return $eval(expr);
12727             } catch (e) {
12728               $exceptionHandler(e);
12729             } finally {
12730               $root.$digest();
12731             }
12732           }
12733       * ```
12734       *
12735       *
12736       * Scope's `$apply()` method transitions through the following stages:
12737       *
12738       * 1. The {@link guide/expression expression} is executed using the
12739       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12740       * 2. Any exceptions from the execution of the expression are forwarded to the
12741       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12742       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12743       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12744       *
12745       *
12746       * @param {(string|function())=} exp An angular expression to be executed.
12747       *
12748       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12749       *    - `function(scope)`: execute the function with current `scope` parameter.
12750       *
12751       * @returns {*} The result of evaluating the expression.
12752       */
12753      $apply: function(expr) {
12754        try {
12755          beginPhase('$apply');
12756          return this.$eval(expr);
12757        } catch (e) {
12758          $exceptionHandler(e);
12759        } finally {
12760          clearPhase();
12761          try {
12762            $rootScope.$digest();
12763          } catch (e) {
12764            $exceptionHandler(e);
12765            throw e;
12766          }
12767        }
12768      },
12769
12770      /**
12771       * @ngdoc method
12772       * @name $rootScope.Scope#$on
12773       * @kind function
12774       *
12775       * @description
12776       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12777       * discussion of event life cycle.
12778       *
12779       * The event listener function format is: `function(event, args...)`. The `event` object
12780       * passed into the listener has the following attributes:
12781       *
12782       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12783       *     `$broadcast`-ed.
12784       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12785       *   - `name` - `{string}`: name of the event.
12786       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12787       *     further event propagation (available only for events that were `$emit`-ed).
12788       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12789       *     to true.
12790       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12791       *
12792       * @param {string} name Event name to listen on.
12793       * @param {function(event, ...args)} listener Function to call when the event is emitted.
12794       * @returns {function()} Returns a deregistration function for this listener.
12795       */
12796      $on: function(name, listener) {
12797        var namedListeners = this.$$listeners[name];
12798        if (!namedListeners) {
12799          this.$$listeners[name] = namedListeners = [];
12800        }
12801        namedListeners.push(listener);
12802
12803        var current = this;
12804        do {
12805          if (!current.$$listenerCount[name]) {
12806            current.$$listenerCount[name] = 0;
12807          }
12808          current.$$listenerCount[name]++;
12809        } while ((current = current.$parent));
12810
12811        var self = this;
12812        return function() {
12813          namedListeners[indexOf(namedListeners, listener)] = null;
12814          decrementListenerCount(self, 1, name);
12815        };
12816      },
12817
12818
12819      /**
12820       * @ngdoc method
12821       * @name $rootScope.Scope#$emit
12822       * @kind function
12823       *
12824       * @description
12825       * Dispatches an event `name` upwards through the scope hierarchy notifying the
12826       * registered {@link ng.$rootScope.Scope#$on} listeners.
12827       *
12828       * The event life cycle starts at the scope on which `$emit` was called. All
12829       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12830       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12831       * registered listeners along the way. The event will stop propagating if one of the listeners
12832       * cancels it.
12833       *
12834       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12835       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12836       *
12837       * @param {string} name Event name to emit.
12838       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12839       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
12840       */
12841      $emit: function(name, args) {
12842        var empty = [],
12843            namedListeners,
12844            scope = this,
12845            stopPropagation = false,
12846            event = {
12847              name: name,
12848              targetScope: scope,
12849              stopPropagation: function() {stopPropagation = true;},
12850              preventDefault: function() {
12851                event.defaultPrevented = true;
12852              },
12853              defaultPrevented: false
12854            },
12855            listenerArgs = concat([event], arguments, 1),
12856            i, length;
12857
12858        do {
12859          namedListeners = scope.$$listeners[name] || empty;
12860          event.currentScope = scope;
12861          for (i=0, length=namedListeners.length; i<length; i++) {
12862
12863            // if listeners were deregistered, defragment the array
12864            if (!namedListeners[i]) {
12865              namedListeners.splice(i, 1);
12866              i--;
12867              length--;
12868              continue;
12869            }
12870            try {
12871              //allow all listeners attached to the current scope to run
12872              namedListeners[i].apply(null, listenerArgs);
12873            } catch (e) {
12874              $exceptionHandler(e);
12875            }
12876          }
12877          //if any listener on the current scope stops propagation, prevent bubbling
12878          if (stopPropagation) return event;
12879          //traverse upwards
12880          scope = scope.$parent;
12881        } while (scope);
12882
12883        return event;
12884      },
12885
12886
12887      /**
12888       * @ngdoc method
12889       * @name $rootScope.Scope#$broadcast
12890       * @kind function
12891       *
12892       * @description
12893       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12894       * registered {@link ng.$rootScope.Scope#$on} listeners.
12895       *
12896       * The event life cycle starts at the scope on which `$broadcast` was called. All
12897       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12898       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12899       * scope and calls all registered listeners along the way. The event cannot be canceled.
12900       *
12901       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12902       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12903       *
12904       * @param {string} name Event name to broadcast.
12905       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12906       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
12907       */
12908      $broadcast: function(name, args) {
12909        var target = this,
12910            current = target,
12911            next = target,
12912            event = {
12913              name: name,
12914              targetScope: target,
12915              preventDefault: function() {
12916                event.defaultPrevented = true;
12917              },
12918              defaultPrevented: false
12919            },
12920            listenerArgs = concat([event], arguments, 1),
12921            listeners, i, length;
12922
12923        //down while you can, then up and next sibling or up and next sibling until back at root
12924        while ((current = next)) {
12925          event.currentScope = current;
12926          listeners = current.$$listeners[name] || [];
12927          for (i=0, length = listeners.length; i<length; i++) {
12928            // if listeners were deregistered, defragment the array
12929            if (!listeners[i]) {
12930              listeners.splice(i, 1);
12931              i--;
12932              length--;
12933              continue;
12934            }
12935
12936            try {
12937              listeners[i].apply(null, listenerArgs);
12938            } catch(e) {
12939              $exceptionHandler(e);
12940            }
12941          }
12942
12943          // Insanity Warning: scope depth-first traversal
12944          // yes, this code is a bit crazy, but it works and we have tests to prove it!
12945          // this piece should be kept in sync with the traversal in $digest
12946          // (though it differs due to having the extra check for $$listenerCount)
12947          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12948              (current !== target && current.$$nextSibling)))) {
12949            while(current !== target && !(next = current.$$nextSibling)) {
12950              current = current.$parent;
12951            }
12952          }
12953        }
12954
12955        return event;
12956      }
12957    };
12958
12959    var $rootScope = new Scope();
12960
12961    return $rootScope;
12962
12963
12964    function beginPhase(phase) {
12965      if ($rootScope.$$phase) {
12966        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12967      }
12968
12969      $rootScope.$$phase = phase;
12970    }
12971
12972    function clearPhase() {
12973      $rootScope.$$phase = null;
12974    }
12975
12976    function compileToFn(exp, name) {
12977      var fn = $parse(exp);
12978      assertArgFn(fn, name);
12979      return fn;
12980    }
12981
12982    function decrementListenerCount(current, count, name) {
12983      do {
12984        current.$$listenerCount[name] -= count;
12985
12986        if (current.$$listenerCount[name] === 0) {
12987          delete current.$$listenerCount[name];
12988        }
12989      } while ((current = current.$parent));
12990    }
12991
12992    /**
12993     * function used as an initial value for watchers.
12994     * because it's unique we can easily tell it apart from other values
12995     */
12996    function initWatchVal() {}
12997  }];
12998}
12999
13000/**
13001 * @description
13002 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
13003 */
13004function $$SanitizeUriProvider() {
13005  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
13006    imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
13007
13008  /**
13009   * @description
13010   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13011   * urls during a[href] sanitization.
13012   *
13013   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13014   *
13015   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
13016   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
13017   * regular expression. If a match is found, the original url is 
13017written into the dom. Otherwise,
13018   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13019   *
13020   * @param {RegExp=} regexp New regexp to whitelist urls with.
13021   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13022   *    chaining otherwise.
13023   */
13024  this.aHrefSanitizationWhitelist = function(regexp) {
13025    if (isDefined(regexp)) {
13026      aHrefSanitizationWhitelist = regexp;
13027      return this;
13028    }
13029    return aHrefSanitizationWhitelist;
13030  };
13031
13032
13033  /**
13034   * @description
13035   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13036   * urls during img[src] sanitization.
13037   *
13038   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13039   *
13040   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
13041   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
13042   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
13043   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13044   *
13045   * @param {RegExp=} regexp New regexp to whitelist urls with.
13046   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13047   *    chaining otherwise.
13048   */
13049  this.imgSrcSanitizationWhitelist = function(regexp) {
13050    if (isDefined(regexp)) {
13051      imgSrcSanitizationWhitelist = regexp;
13052      return this;
13053    }
13054    return imgSrcSanitizationWhitelist;
13055  };
13056
13057  this.$get = function() {
13058    return function sanitizeUri(uri, isImage) {
13059      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
13060      var normalizedVal;
13061      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
13062      if (!msie || msie >= 8 ) {
13063        normalizedVal = urlResolve(uri).href;
13064        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
13065          return 'unsafe:'+normalizedVal;
13066        }
13067      }
13068      return uri;
13069    };
13070  };
13071}
13072
13073var $sceMinErr = minErr('$sce');
13074
13075var SCE_CONTEXTS = {
13076  HTML: 'html',
13077  CSS: 'css',
13078  URL: 'url',
13079  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
13080  // url.  (e.g. ng-include, script src, templateUrl)
13081  RESOURCE_URL: 'resourceUrl',
13082  JS: 'js'
13083};
13084
13085// Helper functions follow.
13086
13087// Copied from:
13088// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
13089// Prereq: s is a string.
13090function escapeForRegexp(s) {
13091  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
13092           replace(/\x08/g, '\\x08');
13093}
13094
13095
13096function adjustMatcher(matcher) {
13097  if (matcher === 'self') {
13098    return matcher;
13099  } else if (isString(matcher)) {
13100    // Strings match exactly except for 2 wildcards - '*' and '**'.
13101    // '*' matches any character except those from the set ':/.?&'.
13102    // '**' matches any character (like .* in a RegExp).
13103    // More than 2 *'s raises an error as it's ill defined.
13104    if (matcher.indexOf('***') > -1) {
13105      throw $sceMinErr('iwcard',
13106          'Illegal sequence *** in string matcher.  String: {0}', matcher);
13107    }
13108    matcher = escapeForRegexp(matcher).
13109                  replace('\\*\\*', '.*').
13110                  replace('\\*', '[^:/.?&;]*');
13111    return new RegExp('^' + matcher + '$');
13112  } else if (isRegExp(matcher)) {
13113    // The only other type of matcher allowed is a Regexp.
13114    // Match entire URL / disallow partial matches.
13115    // Flags are reset (i.e. no global, ignoreCase or multiline)
13116    return new RegExp('^' + matcher.source + '$');
13117  } else {
13118    throw $sceMinErr('imatcher',
13119        'Matchers may only be "self", string patterns or RegExp objects');
13120  }
13121}
13122
13123
13124function adjustMatchers(matchers) {
13125  var adjustedMatchers = [];
13126  if (isDefined(matchers)) {
13127    forEach(matchers, function(matcher) {
13128      adjustedMatchers.push(adjustMatcher(matcher));
13129    });
13130  }
13131  return adjustedMatchers;
13132}
13133
13134
13135/**
13136 * @ngdoc service
13137 * @name $sceDelegate
13138 * @kind function
13139 *
13140 * @description
13141 *
13142 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
13143 * Contextual Escaping (SCE)} services to AngularJS.
13144 *
13145 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
13146 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
13147 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
13148 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
13149 * work because `$sce` delegates to `$sceDelegate` for these operations.
13150 *
13151 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
13152 *
13153 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
13154 * can override it completely to change the behavior of `$sce`, the common case would
13155 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
13156 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
13157 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
13158 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
13159 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13160 */
13161
13162/**
13163 * @ngdoc provider
13164 * @name $sceDelegateProvider
13165 * @description
13166 *
13167 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
13168 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
13169 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
13170 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
13171 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13172 *
13173 * For the general details about this service in Angular, read the main page for {@link ng.$sce
13174 * Strict Contextual Escaping (SCE)}.
13175 *
13176 * **Example**:  Consider the following case. <a name="example"></a>
13177 *
13178 * - your app is hosted at url `http://myapp.example.com/`
13179 * - but some of your templates are hosted on other domains you control such as
13180 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
13181 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
13182 *
13183 * Here is what a secure configuration for this scenario might look like:
13184 *
13185 * ```
13186 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
13187 *    $sceDelegateProvider.resourceUrlWhitelist([
13188 *      // Allow same origin resource loads.
13189 *      'self',
13190 *      // Allow loading from our assets domain.  Notice the difference between * and **.
13191 *      'http://srv*.assets.example.com/**'
13192 *    ]);
13193 *
13194 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
13195 *    $sceDelegateProvider.resourceUrlBlacklist([
13196 *      'http://myapp.example.com/clickThru**'
13197 *    ]);
13198 *  });
13199 * ```
13200 */
13201
13202function $SceDelegateProvider() {
13203  this.SCE_CONTEXTS = SCE_CONTEXTS;
13204
13205  // Resource URLs can also be trusted by policy.
13206  var resourceUrlWhitelist = ['self'],
13207      resourceUrlBlacklist = [];
13208
13209  /**
13210   * @ngdoc method
13211   * @name $sceDelegateProvider#resourceUrlWhitelist
13212   * @kind function
13213   *
13214   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
13215   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13216   *     changes to the array are ignored.
13217   *
13218   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13219   *     allowed in this array.
vendor: 4,150 bytes, lines 13220-13344
13220   *
13221   *     Note: **an empty whitelist array will block all URLs**!
13222   *
13223   * @return {Array} the currently set whitelist array.
13224   *
13225   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
13226   * same origin resource requests.
13227   *
13228   * @description
13229   * Sets/Gets the whitelist of trusted resource URLs.
13230   */
13231  this.resourceUrlWhitelist = function (value) {
13232    if (arguments.length) {
13233      resourceUrlWhitelist = adjustMatchers(value);
13234    }
13235    return resourceUrlWhitelist;
13236  };
13237
13238  /**
13239   * @ngdoc method
13240   * @name $sceDelegateProvider#resourceUrlBlacklist
13241   * @kind function
13242   *
13243   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
13244   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13245   *     changes to the array are ignored.
13246   *
13247   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13248   *     allowed in this array.
13249   *
13250   *     The typical usage for the blacklist is to **block
13251   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13252   *     these would otherwise be trusted but actually return content from the redirected domain.
13253   *
13254   *     Finally, **the blacklist overrides the whitelist** and has the final say.
13255   *
13256   * @return {Array} the currently set blacklist array.
13257   *
13258   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13259   * is no blacklist.)
13260   *
13261   * @description
13262   * Sets/Gets the blacklist of trusted resource URLs.
13263   */
13264
13265  this.resourceUrlBlacklist = function (value) {
13266    if (arguments.length) {
13267      resourceUrlBlacklist = adjustMatchers(value);
13268    }
13269    return resourceUrlBlacklist;
13270  };
13271
13272  this.$get = ['$injector', function($injector) {
13273
13274    var htmlSanitizer = function htmlSanitizer(html) {
13275      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13276    };
13277
13278    if ($injector.has('$sanitize')) {
13279      htmlSanitizer = $injector.get('$sanitize');
13280    }
13281
13282
13283    function matchUrl(matcher, parsedUrl) {
13284      if (matcher === 'self') {
13285        return urlIsSameOrigin(parsedUrl);
13286      } else {
13287        // definitely a regex.  See adjustMatchers()
13288        return !!matcher.exec(parsedUrl.href);
13289      }
13290    }
13291
13292    function isResourceUrlAllowedByPolicy(url) {
13293      var parsedUrl = urlResolve(url.toString());
13294      var i, n, allowed = false;
13295      // Ensure that at least one item from the whitelist allows this url.
13296      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13297        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13298          allowed = true;
13299          break;
13300        }
13301      }
13302      if (allowed) {
13303        // Ensure that no item from the blacklist blocked this url.
13304        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13305          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13306            allowed = false;
13307            break;
13308          }
13309        }
13310      }
13311      return allowed;
13312    }
13313
13314    function generateHolderType(Base) {
13315      var holderType = function TrustedValueHolderType(trustedValue) {
13316        this.$$unwrapTrustedValue = function() {
13317          return trustedValue;
13318        };
13319      };
13320      if (Base) {
13321        holderType.prototype = new Base();
13322      }
13323      holderType.prototype.valueOf = function sceValueOf() {
13324        return this.$$unwrapTrustedValue();
13325      };
13326      holderType.prototype.toString = function sceToString() {
13327        return this.$$unwrapTrustedValue().toString();
13328      };
13329      return holderType;
13330    }
13331
13332    var trustedValueHolderBase = generateHolderType(),
13333        byType = {};
13334
13335    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13336    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13337    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13338    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13339    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13340
13341    /**
13342     * @ngdoc method
13343     * @name $sceDelegate#trustAs
13344     *
13345     * @description
13346     * Returns an object that is trusted by angular for use in specified strict
13347     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13348     * attribute interpolation, any dom event binding attribute interpolation
13349     * such as for onclick,  etc.) that uses the provided value.
13350     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13351     *
13352     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13353     *   resourceUrl, html, js and css.
13354     * @param {*} value The value that that should be considered trusted/safe.
13355     * @returns {*} A value that can be used to stand in for the provided `value` in places
13356     * where Angular expects a $sce.trustAs() return value.
13357     */
13358    function trustAs(type, trustedValue) {
13359      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13360      if (!Constructor) {
13361        throw $sceMinErr('icontext',
13362            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13363            type, trustedValue);
13364      }
13365      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13366        return trustedValue;
13367      }
13368      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13369      // mutable objects, we ensure here that the value passed in is actually a string.
13370      if (typeof trustedValue !== 'string') {
13371        throw $sceMinErr('itype',
13372            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13373            type);
13374      }
13375      return new Constructor(trustedValue);
13376    }
13377
13378    /**
13379     * @ngdoc method
13380     * @name $sceDelegate#valueOf
13381     *
13382     * @description
13383     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13384     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13385     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13386     *
13387     * If the passed parameter is not a value that had been returned by {@link
13388     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13389     *
13390     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13391     *      call or anything else.
13392     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13393     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13394     *     `value` unchanged.
13395     */
13396    function valueOf(maybeTrusted) {
13397      if (maybeTrusted instanceof trustedValueHolderBase) {
13398        return maybeTrusted.$$unwrapTrustedValue();
13399      } else {
13400        return maybeTrusted;
13401      }
13402    }
13403
13404    /**
13405     * @ngdoc method
13406     * @name $sceDelegate#getTrusted
13407     *
13408     * @description
13409     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13410     * returns the originally supplied value if the queried context type is a supertype of the
13411     * created type.  If this condition isn't satisfied, throws an exception.
13412     *
13413     * @param {string} type The kind of context in which this value is to be used.
13414     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13415     *     `$sceDelegate.trustAs`} call.
13416     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13417     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13418     */
13419    function getTrusted(type, maybeTrusted) {
13420      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13421        return maybeTrusted;
13422      }
13423      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13424      if (constructor && maybeTrusted instanceof constructor) {
13425        return maybeTrusted.$$unwrapTrustedValue();
13426      }
13427      // If we get here, then we may only take one of two actions.
13428      // 1. sanitize the value for the requested type, or
13429      // 2. throw an exception.
13430      if (type === SCE_CONTEXTS.RESOURCE_URL) {
13431        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13432          return maybeTrusted;
13433        } else {
13434          throw $sceMinErr('insecurl',
13435              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13436              maybeTrusted.toString());
13437        }
13438      } else if (type === SCE_CONTEXTS.HTML) {
13439        return htmlSanitizer(maybeTrusted);
13440      }
13441      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13442    }
13443
13444    return { trustAs: trustAs,
13445             getTrusted: getTrusted,
13446             valueOf: valueOf };
13447  }];
13448}
13449
13450
13451/**
13452 * @ngdoc provider
13453 * @name $sceProvider
13454 * @description
13455 *
13456 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13457 * -   enable/disable Strict Contextual Escaping (SCE) in a module
13458 * -   override the default implementation with a custom delegate
13459 *
13460 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13461 */
13462
13463/* jshint maxlen: false*/
13464
13465/**
13466 * @ngdoc service
13467 * @name $sce
13468 * @kind function
13469 *
13470 * @description
13471 *
13472 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13473 *
13474 * # Strict Contextual Escaping
13475 *
13476 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13477 * contexts to result in a value that is marked as safe to use for that context.  One example of
13478 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13479 * to these contexts as privileged or SCE contexts.
13480 *
13481 * As of version 1.2, Angular ships with SCE enabled by default.
13482 *
13483 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13484 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13485 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13486 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13487 * to the top of your HTML document.
13488 *
13489 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13490 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13491 *
13492 * Here's an example of a binding in a privileged context:
13493 *
13494 * ```
13495 * <input ng-model="userHtml">
13496 * <div ng-bind-html="userHtml"></div>
13497 * ```
13498 *
13499 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13500 * disabled, this application allows the user to render arbitrary HTML into the DIV.
13501 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13502 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13503 * security vulnerabilities.)
13504 *
13505 * For the case of HTML, you might use a library, either on the client side, or on the server side,
13506 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13507 *
13508 * How would you ensure that every place that used these types of bindings was bound to a value that
13509 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13510 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13511 * properties/fields and forgot to update the binding to the sanitized value?
13512 *
13513 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13514 * determine that something explicitly says it's safe to use a value for binding in that
13515 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13516 * for those values that you can easily tell are safe - because they were received from your server,
13517 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13518 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13519 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13520 *
13521 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13522 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13523 * obtain values that will be accepted by SCE / privileged contexts.
13524 *
13525 *
13526 * ## How does it work?
13527 *
13528 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13529 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13530 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13531 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13532 *
13533 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13534 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13535 * simplified):
13536 *
13537 * ```
13538 * var ngBindHtmlDirective = ['$sce', function($sce) {
13539 *   return function(scope, element, attr) {
13540 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13541 *       element.html(value || '');
13542 *     });
13543 *   };
13544 * }];
13545 * ```
13546 *
13547 * ## Impact on loading templates
13548 *
13549 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13550 * `templateUrl`'s specified by {@link guide/directive directives}.
13551 *
13552 * By default, Angular only loads templates from the same domain and protocol as the application
13553 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13554 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13555 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13556 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13557 *
13558 * *Please note*:
13559 * The browser's
13560 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13561 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13562 * policy apply in addition to this and may further restrict whether the template is successfully
13563 * loaded.  This means that without the right CORS policy, loading templates from a different domain
13564 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13565 * browsers.
13566 *
13567 * ## This feels like too much overhead for the developer?
13568 *
13569 * It's important to remember that SCE only applies to interpolation expressions.
13570 *
13571 * If your expressions are constant literals, they're automatically trusted and you don't need to
13572 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13573 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13574 *
13575 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13576 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13577 *
13578 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13579 * templates in `ng-include` from your application's domain without having to even know about SCE.
13580 * It blocks loading templates from other domains or loading templates over http from an https
13581 * served document.  You can change these by setting your own custom {@link
13582 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13583 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13584 *
13585 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13586 * application that's secure and can be audited to verify that with much more ease than bolting
13587 * security onto an application later.
13588 *
13589 * <a name="contexts"></a>
13590 * ## What trusted context types are supported?
13591 *
13592 * | Context             | Notes          |
13593 * |---------------------|----------------|
13594 * | `$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. |
13595 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13596 * | `$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. |
13597 * | `$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. |
13598 * | `$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. |
13599 *
13600 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13601 *
13602 *  Each element in these arrays must be one of the following:
13603 *
13604 *  - **'self'**
13605 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13606 *      domain** as the application document using the **same protocol**.
13607 *  - **String** (except the special value `'self'`)
13608 *    - The string is matched against the full *normalized / absolute URL* of the resource
13609 *      being tested (substring matches are not good enough.)
13610 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13611 *      match themselves.
13612 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13613 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13614 *      in a whitelist.
13615 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13616 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13617 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13618 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
13619 *      http://foo.example.com/templates/**).
13620 *  - **RegExp** (*see caveat below*)
13621 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13622 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13623 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13624 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13625 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13626 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13627 *      is highly recommended to use the string patterns and only fall back to regular expressions
13628 *      if they as a last resort.
13629 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13630 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13631 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13632 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13633 *    - If you are generating your JavaScript from some other templating engine (not
13634 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13635 *      remember to escape your regular expression (and be aware that you might need more than
13636 *      one level of escaping depending on your templating engine and the way you interpolated
13637 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13638 *      enough before coding your own.  e.g. Ruby has
13639 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13640 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13641 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13642 *      Closure library's [goog.string.regExpEscape(s)](
13643 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13644 *
13645 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13646 *
13647 * ## Show me an example using SCE.
13648 *
13649 * <example module="mySceApp" deps="angular-sanitize.js">
13650 * <file name="index.html">
13651 *   <div ng-controller="myAppController as myCtrl">
13652 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13653 *     <b>User comments</b><br>
13654 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13655 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13656 *     exploit.
13657 *     <div class="well">
13658 *       <div ng-repeat="userComment in myCtrl.userComments">
13659 *         <b>{{userComment.name}}</b>:
13660 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13661 *         <br>
13662 *       </div>
13663 *     </div>
13664 *   </div>
13665 * </file>
13666 *
13667 * <file name="script.js">
13668 *   var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13669 *
13670 *   mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13671 *     var self = this;
13672 *     $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13673 *       self.userComments = userComments;
13674 *     });
13675 *     self.explicitlyTrustedHtml = $sce.trustAsHtml(
13676 *         '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13677 *         'sanitization.&quot;">Hover over this text.</span>');
13678 *   });
13679 * </file>
13680 *
13681 * <file name="test_data.json">
13682 * [
13683 *   { "name": "Alice",
13684 *     "htmlComment":
13685 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13686 *   },
13687 *   { "name": "Bob",
13688 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13689 *   }
13690 * ]
13691 * </file>
13692 *
13693 * <file name="protractor.js" type="protractor">
13694 *   describe('SCE doc demo', function() {
13695 *     it('should sanitize untrusted values', function() {
13696 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
13697 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
13698 *     });
13699 *
13700 *     it('should NOT sanitize explicitly trusted values', function() {
13701 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13702 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13703 *           'sanitization.&quot;">Hover over this text.</span>');
13704 *     });
13705 *   });
13706 * </file>
13707 * </example>
13708 *
13709 *
13710 *
13711 * ## Can I disable SCE completely?
13712 *
13713 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13714 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13715 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13716 * for cases where you have a lot of existing code that was written before SCE was introduced and
13717 * you're migrating them a module at a time.
13718 *
13719 * That said, here's how you can completely disable SCE:
13720 *
13721 * ```
13722 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13723 *   // Completely disable SCE.  For demonstration purposes only!
13724 *   // Do not use in new projects.
13725 *   $sceProvider.enabled(false);
13726 * });
13727 * ```
13728 *
13729 */
13730/* jshint maxlen: 100 */
13731
13732function $SceProvider() {
13733  var enabled = true;
13734
13735  /**
13736   * @ngdoc method
13737   * @name $sceProvider#enabled
13738   * @kind function
13739   *
13740   * @param {boolean=} value If provided, then enables/disables SCE.
13741   * @return {boolean} true if SCE is enabled, false otherwise.
13742   *
13743   * @description
13744   * Enables/disables SCE and returns the current value.
13745   */
13746  this.enabled = function (value) {
13747    if (arguments.length) {
13748      enabled = !!value;
13749    }
13750    return enabled;
13751  };
13752
13753
13754  /* Design notes on the default implementation for SCE.
13755   *
13756   * The API contract for the SCE delegate
13757   * -------------------------------------
13758   * The SCE delegate object must provide the following 3 methods:
13759   *
13760   * - trustAs(contextEnum, value)
13761   *     This method is used to tell the SCE service that the provided value is OK to use in the
13762   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13763   *     getTrusted() for a compatible contextEnum and return this value.
13764   *
13765   * - valueOf(value)
13766   *     For values that were not produced by trustAs(), return them as is.  For values that were
13767   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13768   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13769   *     such a value.
13770   *
13771   * - getTrusted(contextEnum, value)
13772   *     This function should return the a value that is safe to use in the context specified by
13773   *     contextEnum or throw and exception otherwise.
13774   *
13775   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13776   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13777   * instance, an implementation could maintain a registry of all trusted objects by context.  In
13778   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13779   * return the same object passed in if it was found in the registry under a compatible context or
13780   * throw an exception otherwise.  An implementation might only wrap values some of the time based
13781   * on some criteria.  getTrusted() might return a value and not throw an exception for special
13782   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13783   *
13784   *
13785   * A note on the inheritance model for SCE contexts
13786   * ------------------------------------------------
13787   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13788   * is purely an implementation details.
13789   *
13790   * The contract is simply this:
13791   *
13792   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13793   *     will also succeed.
13794   *
13795   * Inheritance happens to capture this in a natural way.  In some future, we
13796   * may not use inheritance anymore.  That is OK because no code outside of
13797   * sce.js and sceSpecs.js would need to be aware of this detail.
13798   */
13799
13800  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13801                $parse,   $sniffer,   $sceDelegate) {
13802    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13803    // the "expression(javascript expression)" syntax which is insecure.
13804    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13805      throw $sceMinErr('iequirks',
13806        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13807        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13808        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13809    }
13810
13811    var sce = shallowCopy(SCE_CONTEXTS);
13812
13813    /**
13814     * @ngdoc method
13815     * @name $sce#isEnabled
13816     * @kind function
13817     *
13818     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13819     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13820     *
13821     * @description
13822     * Returns a boolean indicating if SCE is enabled.
13823     */
13824    sce.isEnabled = function () {
13825      return enabled;
13826    };
13827    sce.trustAs = $sceDelegate.trustAs;
13828    sce.getTrusted = $sceDelegate.getTrusted;
13829    sce.valueOf = $sceDelegate.valueOf;
13830
13831    if (!enabled) {
13832      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13833      sce.valueOf = identity;
13834    }
13835
13836    /**
13837     * @ngdoc method
13838     * @name $sce#parseAs
13839     *
13840     * @description
13841     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13842     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13843     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
13844     * *result*)}
13845     *
13846     * @param {string} type The kind of SCE context in which this result will be used.
13847     * @param {string} expression String expression to compile.
13848     * @returns {function(context, locals)} a function which represents the compiled expression:
13849     *
13850     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13851     *      are evaluated against (typically a scope object).
13852     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13853     *      `context`.
13854     */
13855    sce.parseAs = function sceParseAs(type, expr) {
13856      var parsed = $parse(expr);
13857      if (parsed.literal && parsed.constant) {
13858        return parsed;
13859      } else {
13860        return function sceParseAsTrusted(self, locals) {
13861          return sce.getTrusted(type, parsed(self, locals));
13862        };
13863      }
13864    };
13865
13866    /**
13867     * @ngdoc method
13868     * @name $sce#trustAs
13869     *
13870     * @description
13871     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
13872     * returns an object that is trusted by angular for use in specified strict contextual
13873     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13874     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13875     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13876     * escaping.
13877     *
13878     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13879     *   resource_url, html, js and css.
13880     * @param {*} value The value that that should be considered trusted/safe.
13881     * @returns {*} A value that can be used to stand in for the provided `value` in places
13882     * where Angular expects a $sce.trustAs() return value.
13883     */
13884
13885    /**
13886     * @ngdoc method
13887     * @name $sce#trustAsHtml
13888     *
13889     * @description
13890     * Shorthand method.  `$sce.trustAsHtml(value)` →
13891     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13892     *
13893     * @param {*} value The value to trustAs.
13894     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
13895     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13896     *     only accept expressions that are either literal constants or are the
13897     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13898     */
13899
13900    /**
13901     * @ngdoc method
13902     * @name $sce#trustAsUrl
13903     *
13904     * @description
13905     * Shorthand method.  `$sce.trustAsUrl(value)` →
13906     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13907     *
13908     * @param {*} value The value to trustAs.
13909     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
13910     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13911     *     only accept expressions that are either literal constants or are the
13912     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13913     */
13914
13915    /**
13916     * @ngdoc method
13917     * @name $sce#trustAsResourceUrl
13918     *
13919     * @description
13920     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13921     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13922     *
13923     * @param {*} value The value to trustAs.
13924     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
13925     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13926     *     only accept expressions that are either literal constants or are the return
13927     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
13928     */
13929
13930    /**
13931     * @ngdoc method
13932     * @name $sce#trustAsJs
13933     *
13934     * @description
13935     * Shorthand method.  `$sce.trustAsJs(value)` →
13936     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13937     *
13938     * @param {*} value The value to trustAs.
13939     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
13940     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13941     *     only accept expressions that are either literal constants or are the
13942     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13943     */
13944
13945    /**
13946     * @ngdoc method
13947     * @name $sce#getTrusted
13948     *
13949     * @description
13950     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
13951     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
13952     * originally supplied value if the queried context type is a supertype of the created type.
13953     * If this condition isn't satisfied, throws an exception.
13954     *
13955     * @param {string} type The kind of context in which this value is to be used.
13956     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
13957     *                         call.
13958     * @returns {*} The value the was originally provided to
13959     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
13960     *              Otherwise, throws an exception.
13961     */
13962
13963    /**
13964     * @ngdoc method
13965     * @name $sce#getTrustedHtml
13966     *
13967     * @description
13968     * Shorthand method.  `$sce.getTrustedHtml(value)` →
13969     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13970     *
13971     * @param {*} value The value to pass to `$sce.getTrusted`.
13972     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13973     */
13974
13975    /**
13976     * @ngdoc method
13977     * @name $sce#getTrustedCss
13978     *
13979     * @description
13980     * Shorthand method.  `$sce.getTrustedCss(value)` →
13981     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13982     *
13983     * @param {*} value The value to pass to `$sce.getTrusted`.
13984     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13985     */
13986
13987    /**
13988     * @ngdoc method
13989     * @name $sce#getTrustedUrl
13990     *
13991     * @description
13992     * Shorthand method.  `$sce.getTrustedUrl(value)` →
13993     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13994     *
13995     * @param {*} value The value to pass to `$sce.getTrusted`.
13996     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13997     */
13998
13999    /**
14000     * @ngdoc method
14001     * @name $sce#getTrustedResourceUrl
14002     *
14003     * @description
14004     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
14005     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
14006     *
14007     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
14008     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
14009     */
14010
14011    /**
14012     * @ngdoc method
14013     * @name $sce#getTrustedJs
14014     *
14015     * @description
14016     * Shorthand method.  `$sce.getTrustedJs(value)` →
14017     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
14018     *
14019     * @param {*} value The value to pass to `$sce.getTrusted`.
14020     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
14021     */
14022
14023    /**
14024     * @ngdoc method
14025     * @name $sce#parseAsHtml
14026     *
14027     * @description
14028     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
14029     *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
14030     *
14031     * @param {string} expression String expression to compile.
14032     * @returns {function(context, locals)} a function which represents the compiled expression:
14033     *
14034     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14035     *      are evaluated against (typically a scope object).
14036     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14037     *      `context`.
14038     */
14039
14040    /**
14041     * @ngdoc method
14042     * @name $sce#parseAsCss
14043     *
14044     * @description
14045     * Shorthand method.  `$sce.parseAsCss(value)` →
14046     *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
14047     *
14048     * @param {string} expression String expression to compile.
14049     * @returns {function(context, locals)} a function which represents the compiled expression:
14050     *
14051     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14052     *      are evaluated against (typically a scope object).
14053     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14054     *      `context`.
14055     */
14056
14057    /**
14058     * @ngdoc method
14059     * @name $sce#parseAsUrl
14060     *
14061     * @description
14062     * Shorthand method.  `$sce.parseAsUrl(value)` →
14063     *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
14064     *
14065     * @param {string} expression String expression to compile.
14066     * @returns {function(context, locals)} a function which represents the compiled expression:
14067     *
14068     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14069     *      are evaluated against (typically a scope object).
14070     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14071     *      `context`.
14072     */
14073
14074    /**
14075     * @ngdoc method
14076     * @name $sce#parseAsResourceUrl
14077     *
14078     * @description
14079     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
14080     *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
14081     *
14082     * @param {string} expression String expression to compile.
14083     * @returns {function(context, locals)} a function which represents the compiled expression:
14084     *
14085     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14086     *      are evaluated against (typically a scope object).
14087     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14088     *      `context`.
14089     */
14090
14091    /**
14092     * @ngdoc method
14093     * @name $sce#parseAsJs
14094     *
14095     * @description
14096     * Shorthand method.  `$sce.parseAsJs(value)` →
14097     *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
14098     *
14099     * @param {string} expression String expression to compile.
14100     * @returns {function(context, locals)} a function which represents the compiled expression:
14101     *
14102     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14103     *      are evaluated against (typically a scope object).
14104     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14105     *      `context`.
14106     */
14107
14108    // Shorthand delegations.
14109    var parse = sce.parseAs,
14110        getTrusted = sce.getTrusted,
14111        trustAs = sce.trustAs;
14112
14113    forEach(SCE_CONTEXTS, function (enumValue, name) {
14114      var lName = lowercase(name);
14115      sce[camelCase("parse_as_" + lName)] = function (expr) {
14116        return parse(enumValue, expr);
14117      };
14118      sce[camelCase("get_trusted_" + lName)] = function (value) {
14119        return getTrusted(enumValue, value);
14120      };
14121      sce[camelCase("trust_as_" + lName)] = function (value) {
14122        return trustAs(enumValue, value);
14123      };
14124    });
14125
14126    return sce;
14127  }];
14128}
14129
14130/**
14131 * !!! This is an undocumented "private" service !!!
14132 *
14133 * @name $sniffer
14134 * @requires $window
14135 * @requires $document
14136 *
14137 * @property {boolean} history Does the browser support html5 history api ?
14138 * @property {boolean} hashchange Does the browser support hashchange event ?
14139 * @property {boolean} transitions Does the browser support CSS transition events ?
14140 * @property {boolean} animations Does the browser support CSS animation events ?
14141 *
14142 * @description
14143 * This is very simple implementation of testing browser's features.
14144 */
14145function $SnifferProvider() {
14146  this.$get = ['$window', '$document', function($window, $document) {
14147    var eventSupport = {},
14148        android =
14149          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
14150        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
14151        document = $document[0] || {},
14152        documentMode = document.documentMode,
14153        vendorPrefix,
14154        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
14155        bodyStyle = document.body && document.body.style,
14156        transitions = false,
14157        animations = false,
14158        match;
14159
14160    if (bodyStyle) {
14161      for(var prop in bodyStyle) {
14162        if(match = vendorRegex.exec(prop)) {
14163          vendorPrefix = match[0];
14164          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
14165          break;
14166        }
14167      }
14168
14169      if(!vendorPrefix) {
14170        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
14171      }
14172
14173      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
14174      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
14175
14176      if (android && (!transitions||!animations)) {
14177        transitions = isString(document.body.style.webkitTransition);
14178        animations = isString(document.body.style.webkitAnimation);
14179      }
14180    }
14181
14182
14183    return {
14184      // Android has history.pushState, but it does not update location correctly
14185      // so let's not use the history API at all.
14186      // http://code.google.com/p/android/issues/detail?id=17471
14187      // https://github.com/angular/angular.js/issues/904
14188
14189      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
14190      // so let's not use the history API also
14191      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
14192      // jshint -W018
14193      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
14194      // jshint +W018
14195      hashchange: 'onhashchange' in $window &&
14196                  // IE8 compatible mode lies
14197                  (!documentMode || documentMode > 7),
14198      hasEvent: function(event) {
14199        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
14200        // it. In particular the event is not fired when backspace or delete key are pressed or
14201        // when cut operation is performed.
14202        if (event == 'input' && msie == 9) return false;
14203
14204        if (isUndefined(eventSupport[event])) {
14205          var divElm = document.createElement('div');
14206          eventSupport[event] = 'on' + event in divElm;
14207        }
14208
14209        return eventSupport[event];
14210      },
14211      csp: csp(),
14212      vendorPrefix: vendorPrefix,
14213      transitions : transitions,
14214      animations : animations,
14215      android: android,
14216      msie : msie,
14217      msieDocumentMode: documentMode
14218    };
14219  }];
14220}
14221
14222function $TimeoutProvider() {
14223  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14224       function($rootScope,   $browser,   $q,   $exceptionHandler) {
14225    var deferreds = {};
14226
14227
14228     /**
14229      * @ngdoc service
14230      * @name $timeout
14231      *
14232      * @description
14233      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
14234      * block and delegates any exceptions to
14235      * {@link ng.$exceptionHandler $exceptionHandler} service.
14236      *
14237      * The return value of registering a timeout function is a promise, which will be resolved when
14238      * the timeout is reached and the timeout function is executed.
14239      *
14240      * To cancel a timeout request, call `$timeout.cancel(promise)`.
14241      *
14242      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
14243      * synchronously flush the queue of deferred functions.
14244      *
14245      * @param {function()} fn A function, whose execution should be delayed.
14246      * @param {number=} [delay=0] Delay in milliseconds.
14247      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14248      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14249      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14250      *   promise will be resolved with is the return value of the `fn` function.
14251      *
14252      */
14253    function timeout(fn, delay, invokeApply) {
14254      var deferred = $q.defer(),
14255          promise = deferred.promise,
14256          skipApply = (isDefined(invokeApply) && !invokeApply),
14257          timeoutId;
14258
14259      timeoutId = $browser.defer(function() {
14260        try {
14261          deferred.resolve(fn());
14262        } catch(e) {
14263          deferred.reject(e);
14264          $exceptionHandler(e);
14265        }
14266        finally {
14267          delete deferreds[promise.$$timeoutId];
14268        }
14269
14270        if (!skipApply) $rootScope.$apply();
14271      }, delay);
14272
14273      promise.$$timeoutId = timeoutId;
14274      deferreds[timeoutId] = deferred;
14275
14276      return promise;
14277    }
14278
14279
14280     /**
14281      * @ngdoc method
14282      * @name $timeout#cancel
14283      *
14284      * @description
14285      * Cancels a task associated with the `promise`. As a result of this, the promise will be
14286      * resolved with a rejection.
14287      *
14288      * @param {Promise=} promise Promise returned by the `$timeout` function.
14289      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14290      *   canceled.
14291      */
14292    timeout.cancel = function(promise) {
14293      if (promise && promise.$$timeoutId in deferreds) {
14294        deferreds[promise.$$timeoutId].reject('canceled');
14295        delete deferreds[promise.$$timeoutId];
14296        return $browser.defer.cancel(promise.$$timeoutId);
14297      }
14298      return false;
14299    };
14300
14301    return timeout;
14302  }];
14303}
14304
14305// NOTE:  The usage of window and document instead of $window and $document here is
14306// deliberate.  This service depends on the specific behavior of anchor nodes created by the
14307// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14308// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14309// doesn't know about mocked locations and resolves URLs to the real document - which is
14310// exactly the behavior needed here.  There is little value is mocking these out for this
14311// service.
14312var urlParsingNode = document.createElement("a");
14313var originUrl = urlResolve(window.location.href, true);
14314
14315
14316/**
14317 *
14318 * Implementation Notes for non-IE browsers
14319 * ----------------------------------------
14320 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14321 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14322 * URL will be resolved into an absolute URL in the context of the application document.
14323 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14324 * properties are all populated to reflect the normalized URL.  This approach has wide
14325 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14326 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14327 *
14328 * Implementation Notes for IE
14329 * ---------------------------
14330 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14331 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14332 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14333 * work around that by performing the parsing in a 2nd step by taking a previously normalized
14334 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14335 * properties such as protocol, hostname, port, etc.
14336 *
14337 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14338 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14339 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14340 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14341 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14342 * method and IE < 8 is unsupported.
14343 *
14344 * References:
14345 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14346 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14347 *   http://url.spec.whatwg.org/#urlutils
14348 *   https://github.com/angular/angular.js/pull/2902
14349 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14350 *
14351 * @kind function
14352 * @param {string} url The URL to be parsed.
14353 * @description Normalizes and parses a URL.
14354 * @returns {object} Returns the normalized URL as a dictionary.
14355 *
14356 *   | member name   | Description    |
14357 *   |---------------|----------------|
14358 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14359 *   | protocol      | The protocol including the trailing colon                              |
14360 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14361 *   | search        | The search params, minus the question mark                             |
14362 *   | hash          | The hash string, minus the hash symbol
14363 *   | hostname      | The hostname
14364 *   | port          | The port, without ":"
14365 *   | pathname      | The pathname, beginning with "/"
14366 *
14367 */
14368function urlResolve(url, base) {
14369  var href = url;
14370
14371  if (msie) {
14372    // Normalize before parse.  Refer Implementation Notes on why this is
14373    // done in two steps on IE.
14374    urlParsingNode.setAttribute("href", href);
14375    href = urlParsingNode.href;
14376  }
14377
14378  urlParsingNode.setAttribute('href', href);
14379
14380  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14381  return {
14382    href: urlParsingNode.href,
14383    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14384    host: urlParsingNode.host,
14385    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14386    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14387    hostname: urlParsingNode.hostname,
14388    port: urlParsingNode.port,
14389    pathname: (urlParsingNode.pathname.charAt(0) === '/')
14390      ? urlParsingNode.pathname
14391      : '/' + urlParsingNode.pathname
14392  };
14393}
14394
14395/**
14396 * Parse a request URL and determine whether this is a same-origin request as the application document.
14397 *
14398 * @param {string|object} requestUrl The url of the request as a string that will be resolved
14399 * or a parsed URL object.
14400 * @returns {boolean} Whether the request is for the same origin as the application document.
14401 */
14402function urlIsSameOrigin(requestUrl) {
14403  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14404  return (parsed.protocol === originUrl.protocol &&
14405          parsed.host === originUrl.host);
14406}
14407
14408/**
14409 * @ngdoc service
14410 * @name $window
14411 *
14412 * @description
14413 * A reference to the browser's `window` object. While `window`
14414 * is globally available in JavaScript, it causes testability problems, because
14415 * it is a global variable. In angular we always refer to it through the
14416 * `$window` service, so it may be overridden, removed or mocked for testing.
14417 *
14418 * Expressions, like the one defined for the `ngClick` directive in the example
14419 * below, are evaluated with respect to the current scope.  Therefore, there is
14420 * no risk of inadvertently coding in a dependency on a global value in such an
14421 * expression.
14422 *
14423 * @example
14424   <example module="windowExample">
14425     <file name="index.html">
14426       <script>
14427         angular.module('windowExample', [])
14428           .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
14429             $scope.greeting = 'Hello, World!';
14430             $scope.doGreeting = function(greeting) {
14431               $window.alert(greeting);
14432             };
14433           }]);
14434       </script>
14435       <div ng-controller="ExampleController">
14436         <input type="text" ng-model="greeting" />
14437         <button ng-click="doGreeting(greeting)">ALERT</button>
14438       </div>
14439     </file>
14440     <file name="protractor.js" type="protractor">
14441      it('should display the greeting in the input box', function() {
14442       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14443       // If we click the button it will block the test runner
14444       // element(':button').click();
14445      });
14446     </file>
14447   </example>
14448 */
14449function $WindowProvider(){
14450  this.$get = valueFn(window);
14451}
14452
14453/* global currencyFilter: true,
14454 dateFilter: true,
14455 filterFilter: true,
14456 jsonFilter: true,
14457 limitToFilter: true,
14458 lowercaseFilter: true,
14459 numberFilter: true,
14460 orderByFilter: true,
14461 uppercaseFilter: true,
14462 */
14463
14464/**
14465 * @ngdoc provider
14466 * @name $filterProvider
14467 * @description
14468 *
14469 * Filters are just functions which transform input to an output. However filters need to be
14470 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14471 * annotated with dependencies and is responsible for creating a filter function.
14472 *
14473 * ```js
14474 *   // Filter registration
14475 *   function MyModule($provide, $filterProvider) {
14476 *     // create a service to demonstrate injection (not always needed)
14477 *     $provide.value('greet', function(name){
14478 *       return 'Hello ' + name + '!';
14479 *     });
14480 *
14481 *     // register a filter factory which uses the
14482 *     // greet service to demonstrate DI.
14483 *     $filterProvider.register('greet', function(greet){
14484 *       // return the filter function which uses the greet service
14485 *       // to generate salutation
14486 *       return function(text) {
14487 *         // filters need to be forgiving so check input validity
14488 *         return text && greet(text) || text;
14489 *       };
14490 *     });
14491 *   }
14492 * ```
14493 *
14494 * The filter function is registered with the `$injector` under the filter name suffix with
14495 * `Filter`.
14496 *
14497 * ```js
14498 *   it('should be the same instance', inject(
14499 *     function($filterProvider) {
14500 *       $filterProvider.register('reverse', function(){
14501 *         return ...;
14502 *       });
14503 *     },
14504 *     function($filter, reverseFilter) {
14505 *       expect($filter('reverse')).toBe(reverseFilter);
14506 *     });
14507 * ```
14508 *
14509 *
14510 * For more information about how angular filters work, and how to create your own filters, see
14511 * {@link guide/filter Filters} in the Angular Developer Guide.
14512 */
14513/**
14514 * @ngdoc method
14515 * @name $filterProvider#register
14516 * @description
14517 * Register filter factory function.
14518 *
14519 * @param {String} name Name of the filter.
14520 * @param {Function} fn The filter factory function which is injectable.
14521 */
14522
14523
14524/**
14525 * @ngdoc service
14526 * @name $filter
14527 * @kind function
14528 * @description
14529 * Filters are used for formatting data displayed to the user.
14530 *
14531 * The general syntax in templates is as follows:
14532 *
14533 *         {{ expression [| filter_name[:parameter_value] ... ] }}
14534 *
14535 * @param {String} name Name of the filter function to retrieve
14536 * @return {Function} the filter function
14537 * @example
14538   <example name="$filter" module="filterExample">
14539     <file name="index.html">
14540       <div ng-controller="MainCtrl">
14541        <h3>{{ originalText }}</h3>
14542        <h3>{{ filteredText }}</h3>
14543       </div>
14544     </file>
14545
14546     <file name="script.js">
14547      angular.module('filterExample', [])
14548      .controller('MainCtrl', function($scope, $filter) {
14549        $scope.originalText = 'hello';
14550        $scope.filteredText = $filter('uppercase')($scope.originalText);
14551      });
14552     </file>
14553   </example>
14554  */
14555$FilterProvider.$inject = ['$provide'];
14556function $FilterProvider($provide) {
14557  var suffix = 'Filter';
14558
14559  /**
14560   * @ngdoc method
14561   * @name $controllerProvider#register
14562   * @param {string|Object} name Name of the filter function, or an object map of filters where
14563   *    the keys are the filter names and the values are the filter factories.
14564   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14565   *    of the registered filter instances.
14566   */
14567  function register(name, factory) {
14568    if(isObject(name)) {
14569      var filters = {};
14570      forEach(name, function(filter, key) {
14571        filters[key] = register(key, filter);
14572      });
14573      return filters;
14574    } else {
14575      return $provide.factory(name + suffix, factory);
14576    }
14577  }
14578  this.register = register;
14579
14580  this.$get = ['$injector', function($injector) {
14581    return function(name) {
14582      return $injector.get(name + suffix);
14583    };
14584  }];
14585
14586  ////////////////////////////////////////
14587
14588  /* global
14589    currencyFilter: false,
14590    dateFilter: false,
14591    filterFilter: false,
14592    jsonFilter: false,
14593    limitToFilter: false,
14594    lowercaseFilter: false,
14595    numberFilter: false,
14596    orderByFilter: false,
14597    uppercaseFilter: false,
14598  */
14599
14600  register('currency', currencyFilter);
14601  register('date', dateFilter);
14602  register('filter', filterFilter);
14603  register('json', jsonFilter);
14604  register('limitTo', limitToFilter);
14605  register('lowercase', lowercaseFilter);
14606  register('number', numberFilter);
14607  register('orderBy', orderByFilter);
14608  register('uppercase', uppercaseFilter);
14609}
14610
14611/**
14612 * @ngdoc filter
14613 * @name filter
14614 * @kind function
14615 *
14616 * @description
14617 * Selects a subset of items from `array` and returns it as a new array.
14618 *
14619 * @param {Array} array The source array.
14620 * @param {string|Object|function()} expression The predicate to be used for selecting items from
14621 *   `array`.
14622 *
14623 *   Can be one of:
14624 *
14625 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14626 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14627 *     will be returned. The predicate can be negated by prefixing the string with `!`.
14628 *
14629 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14630 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14631 *     which have property `name` containing "M" and property `phone` containing "1". A special
14632 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14633 *     property of the object. That's equivalent to the simple substring match with a `string`
14634 *     as described above.
14635 *
14636 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14637 *     called for each element of `array`. The final result is an array of those elements that
14638 *     the predicate returned true for.
14639 *
14640 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14641 *     determining if the expected value (from the filter expression) and actual value (from
14642 *     the object in the array) should be considered a match.
14643 *
14644 *   Can be one of:
14645 *
14646 *   - `function(actual, expected)`:
14647 *     The function will be given the object value and the predicate value to compare and
14648 *     should return true if the item should be included in filtered result.
14649 *
14650 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14651 *     this is essentially strict comparison of expected and actual.
14652 *
14653 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
14654 *     insensitive way.
14655 *
14656 * @example
14657   <example>
14658     <file name="index.html">
14659       <div ng-init="friends = [{name:'John', phone:'555-1276'},
14660                                {name:'Mary', phone:'800-BIG-MARY'},
14661                                {name:'Mike', phone:'555-4321'},
14662                                {name:'Adam', phone:'555-5678'},
14663                                {name:'Julie', phone:'555-8765'},
14664                                {name:'Juliette', phone:'555-5678'}]"></div>
14665
14666       Search: <input ng-model="searchText">
14667       <table id="searchTextResults">
14668         <tr><th>Name</th><th>Phone</th></tr>
14669         <tr ng-repeat="friend in friends | filter:searchText">
14670           <td>{{friend.name}}</td>
14671           <td>{{friend.phone}}</td>
14672         </tr>
14673       </table>
14674       <hr>
14675       Any: <input ng-model="search.$"> <br>
14676       Name only <input ng-model="search.name"><br>
14677       Phone only <input ng-model="search.phone"><br>
14678       Equality <input type="checkbox" ng-model="strict"><br>
14679       <table id="searchObjResults">
14680         <tr><th>
14680Name</th><th>Phone</th></tr>
14681         <tr ng-repeat="friendObj in friends | filter:search:strict">
14682           <td>{{friendObj.name}}</td>
14683           <td>{{friendObj.phone}}</td>
14684         </tr>
14685       </table>
14686     </file>
14687     <file name="protractor.js" type="protractor">
14688       var expectFriendNames = function(expectedNames, key) {
14689         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14690           arr.forEach(function(wd, i) {
14691             expect(wd.getText()).toMatch(expectedNames[i]);
14692           });
14693         });
14694       };
14695
14696       it('should search across all fields when filtering with a string', function() {
14697         var searchText = element(by.model('searchText'));
14698         searchText.clear();
14699         searchText.sendKeys('m');
14700         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14701
14702         searchText.clear();
14703         searchText.sendKeys('76');
14704         expectFriendNames(['John', 'Julie'], 'friend');
14705       });
14706
14707       it('should search in specific fields when filtering with a predicate object', function() {
14708         var searchAny = element(by.model('search.$'));
14709         searchAny.clear();
14710         searchAny.sendKeys('i');
14711         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14712       });
14713       it('should use a equal comparison when comparator is true', function() {
14714         var searchName = element(by.model('search.name'));
14715         var strict = element(by.model('strict'));
14716         searchName.clear();
14717         searchName.sendKeys('Julie');
14718         strict.click();
14719         expectFriendNames(['Julie'], 'friendObj');
14720       });
14721     </file>
14722   </example>
14723 */
14724function filterFilter() {
14725  return function(array, expression, comparator) {
14726    if (!isArray(array)) return array;
14727
14728    var comparatorType = typeof(comparator),
14729        predicates = [];
14730
14731    predicates.check = function(value) {
14732      for (var j = 0; j < predicates.length; j++) {
14733        if(!predicates[j](value)) {
14734          return false;
14735        }
14736      }
14737      return true;
14738    };
14739
14740    if (comparatorType !== 'function') {
14741      if (comparatorType === 'boolean' && comparator) {
14742        comparator = function(obj, text) {
14743          return angular.equals(obj, text);
14744        };
14745      } else {
14746        comparator = function(obj, text) {
14747          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14748            for (var objKey in obj) {
14749              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14750                  comparator(obj[objKey], text[objKey])) {
14751                return true;
14752              }
14753            }
14754            return false;
14755          }
14756          text = (''+text).toLowerCase();
14757          return (''+obj).toLowerCase().indexOf(text) > -1;
14758        };
14759      }
14760    }
14761
14762    var search = function(obj, text){
14763      if (typeof text == 'string' && text.charAt(0) === '!') {
14764        return !search(obj, text.substr(1));
14765      }
14766      switch (typeof obj) {
14767        case "boolean":
14768        case "number":
14769        case "string":
14770          return comparator(obj, text);
14771        case "object":
14772          switch (typeof text) {
14773            case "object":
14774              return comparator(obj, text);
14775            default:
14776              for ( var objKey in obj) {
14777                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14778                  return true;
14779                }
14780              }
14781              break;
14782          }
14783          return false;
14784        case "array":
14785          for ( var i = 0; i < obj.length; i++) {
14786            if (search(obj[i], text)) {
14787              return true;
14788            }
14789          }
14790          return false;
14791        default:
14792          return false;
14793      }
14794    };
14795    switch (typeof expression) {
14796      case "boolean":
14797      case "number":
14798      case "string":
14799        // Set up expression object and fall through
14800        expression = {$:expression};
14801        // jshint -W086
14802      case "object":
14803        // jshint +W086
14804        for (var key in expression) {
14805          (function(path) {
14806            if (typeof expression[path] === 'undefined') return;
14807            predicates.push(function(value) {
14808              return search(path == '$' ? value : (value && value[path]), expression[path]);
14809            });
14810          })(key);
14811        }
14812        break;
14813      case 'function':
14814        predicates.push(expression);
14815        break;
14816      default:
14817        return array;
14818    }
14819    var filtered = [];
14820    for ( var j = 0; j < array.length; j++) {
14821      var value = array[j];
14822      if (predicates.check(value)) {
14823        filtered.push(value);
14824      }
14825    }
14826    return filtered;
14827  };
14828}
14829
14830/**
14831 * @ngdoc filter
14832 * @name currency
14833 * @kind function
14834 *
14835 * @description
14836 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14837 * symbol for current locale is used.
14838 *
14839 * @param {number} amount Input to filter.
14840 * @param {string=} symbol Currency symbol or identifier to be displayed.
14841 * @returns {string} Formatted number.
14842 *
14843 *
14844 * @example
14845   <example module="currencyExample">
14846     <file name="index.html">
14847       <script>
14848         angular.module('currencyExample', [])
14849           .controller('ExampleController', ['$scope', function($scope) {
14850             $scope.amount = 1234.56;
14851           }]);
14852       </script>
14853       <div ng-controller="ExampleController">
14854         <input type="number" ng-model="amount"> <br>
14855         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14856         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14857       </div>
14858     </file>
14859     <file name="protractor.js" type="protractor">
14860       it('should init with 1234.56', function() {
14861         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14862         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14863       });
14864       it('should update', function() {
14865         if (browser.params.browser == 'safari') {
14866           // Safari does not understand the minus key. See
14867           // https://github.com/angular/protractor/issues/481
14868           return;
14869         }
14870         element(by.model('amount')).clear();
14871         element(by.model('amount')).sendKeys('-1234');
14872         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14873         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14874       });
14875     </file>
14876   </example>
14877 */
14878currencyFilter.$inject = ['$locale'];
14879function currencyFilter($locale) {
14880  var formats = $locale.NUMBER_FORMATS;
14881  return function(amount, currencySymbol){
14882    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14883    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14884                replace(/\u00A4/g, currencySymbol);
14885  };
14886}
14887
14888/**
14889 * @ngdoc filter
14890 * @name number
14891 * @kind function
14892 *
14893 * @description
14894 * Formats a number as text.
14895 *
14896 * If the input is not a number an empty string is returned.
14897 *
14898 * @param {number|string} number Number to format.
14899 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14900 * If this is not provided then the fraction size is computed from the current locale's number
14901 * formatting pattern. In the case of the default locale, it will be 3.
14902 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14903 *
14904 * @example
14905   <example module="numberFilterExample">
14906     <file name="index.html">
14907       <script>
14908         angular.module('numberFilterExample', [])
14909           .controller('ExampleController', ['$scope', function($scope) {
14910             $scope.val = 1234.56789;
14911           }]);
14912       </script>
14913       <div ng-controller="ExampleController">
14914         Enter number: <input ng-model='val'><br>
14915         Default formatting: <span id='number-default'>{{val | number}}</span><br>
14916         No fractions: <span>{{val | number:0}}</span><br>
14917         Negative number: <span>{{-val | number:4}}</span>
14918       </div>
14919     </file>
14920     <file name="protractor.js" type="protractor">
14921       it('should format numbers', function() {
14922         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14923         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14924         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14925       });
14926
14927       it('should update', function() {
14928         element(by.model('val')).clear();
14929         element(by.model('val')).sendKeys('3374.333');
14930         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14931         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14932         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14933      });
14934     </file>
14935   </example>
14936 */
14937
14938
14939numberFilter.$inject = ['$locale'];
14940function numberFilter($locale) {
14941  var formats = $locale.NUMBER_FORMATS;
14942  return function(number, fractionSize) {
14943    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14944      fractionSize);
14945  };
14946}
14947
14948var DECIMAL_SEP = '.';
14949function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14950  if (number == null || !isFinite(number) || isObject(number)) return '';
14951
14952  var isNegative = number < 0;
14953  number = Math.abs(number);
14954  var numStr = number + '',
14955      formatedText = '',
14956      parts = [];
14957
14958  var hasExponent = false;
14959  if (numStr.indexOf('e') !== -1) {
14960    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14961    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14962      numStr = '0';
14963      number = 0;
14964    } else {
14965      formatedText = numStr;
14966      hasExponent = true;
14967    }
14968  }
14969
14970  if (!hasExponent) {
14971    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14972
14973    // determine fractionSize if it is not specified
14974    if (isUndefined(fractionSize)) {
14975      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14976    }
14977
14978    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
14979    // inspired by:
14980    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
14981    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
14982
14983    var fraction = ('' + number).split(DECIMAL_SEP);
14984    var whole = fraction[0];
14985    fraction = fraction[1] || '';
14986
14987    var i, pos = 0,
14988        lgroup = pattern.lgSize,
14989        group = pattern.gSize;
14990
14991    if (whole.length >= (lgroup + group)) {
14992      pos = whole.length - lgroup;
14993      for (i = 0; i < pos; i++) {
14994        if ((pos - i)%group === 0 && i !== 0) {
14995          formatedText += groupSep;
14996        }
14997        formatedText += whole.charAt(i);
14998      }
14999    }
15000
15001    for (i = pos; i < whole.length; i++) {
15002      if ((whole.length - i)%lgroup === 0 && i !== 0) {
15003        formatedText += groupSep;
15004      }
15005      formatedText += whole.charAt(i);
15006    }
15007
15008    // format fraction part.
15009    while(fraction.length < fractionSize) {
15010      fraction += '0';
15011    }
15012
15013    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
15014  } else {
15015
15016    if (fractionSize > 0 && number > -1 && number < 1) {
15017      formatedText = number.toFixed(fractionSize);
15018    }
15019  }
15020
15021  parts.push(isNegative ? pattern.negPre : pattern.posPre);
15022  parts.push(formatedText);
15023  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
15024  return parts.join('');
15025}
15026
15027function padNumber(num, digits, trim) {
15028  var neg = '';
15029  if (num < 0) {
15030    neg =  '-';
15031    num = -num;
15032  }
15033  num = '' + num;
15034  while(num.length < digits) num = '0' + num;
15035  if (trim)
15036    num = num.substr(num.length - digits);
15037  return neg + num;
15038}
15039
15040
15041function dateGetter(name, size, offset, trim) {
15042  offset = offset || 0;
15043  return function(date) {
15044    var value = date['get' + name]();
15045    if (offset > 0 || value > -offset)
15046      value += offset;
15047    if (value === 0 && offset == -12 ) value = 12;
15048    return padNumber(value, size, trim);
15049  };
15050}
15051
15052function dateStrGetter(name, shortForm) {
15053  return function(date, formats) {
15054    var value = date['get' + name]();
15055    var get = uppercase(shortForm ? ('SHORT' + name) : name);
15056
15057    return formats[get][value];
15058  };
15059}
15060
15061function timeZoneGetter(date) {
15062  var zone = -1 * date.getTimezoneOffset();
15063  var paddedZone = (zone >= 0) ? "+" : "";
15064
15065  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
15066                padNumber(Math.abs(zone % 60), 2);
15067
15068  return paddedZone;
15069}
15070
15071function ampmGetter(date, formats) {
15072  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
15073}
15074
15075var DATE_FORMATS = {
15076  yyyy: dateGetter('FullYear', 4),
15077    yy: dateGetter('FullYear', 2, 0, true),
15078     y: dateGetter('FullYear', 1),
15079  MMMM: dateStrGetter('Month'),
15080   MMM: dateStrGetter('Month', true),
15081    MM: dateGetter('Month', 2, 1),
15082     M: dateGetter('Month', 1, 1),
15083    dd: dateGetter('Date', 2),
15084     d: dateGetter('Date', 1),
15085    HH: dateGetter('Hours', 2),
15086     H: dateGetter('Hours', 1),
15087    hh: dateGetter('Hours', 2, -12),
15088     h: dateGetter('Hours', 1, -12),
15089    mm: dateGetter('Minutes', 2),
15090     m: dateGetter('Minutes', 1),
15091    ss: dateGetter('Seconds', 2),
15092     s: dateGetter('Seconds', 1),
15093     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
15094     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
15095   sss: dateGetter('Milliseconds', 3),
15096  EEEE: dateStrGetter('Day'),
15097   EEE: dateStrGetter('Day', true),
15098     a: ampmGetter,
15099     Z: timeZoneGetter
15100};
15101
15102var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
15103    NUMBER_STRING = /^\-?\d+$/;
15104
15105/**
15106 * @ngdoc filter
15107 * @name date
15108 * @kind function
15109 *
15110 * @description
15111 *   Formats `date` to a string based on the requested `format`.
15112 *
15113 *   `format` string can be composed of the following elements:
15114 *
15115 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
15116 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
15117 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
15118 *   * `'MMMM'`: Month in year (January-December)
15119 *   * `'MMM'`: Month in year (Jan-Dec)
15120 *   * `'MM'`: Month in year, padded (01-12)
15121 *   * `'M'`: Month in year (1-12)
15122 *   * `'dd'`: Day in month, padded (01-31)
15123 *   * `'d'`: Day in month (1-31)
15124 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
15125 *   * `'EEE'`: Day in Week, (Sun-Sat)
15126 *   * `'HH'`: Hour in day, padded (00-23)
15127 *   * `'H'`: Hour in day (0-23)
15128 *   * `'hh'`: Hour in am/pm, padded (01-12)
15129 *   * `'h'`: Hour in am/pm, (1-12)
15130 *   * `'mm'`: Minute in hour, padded (00-59)
15131 *   * `'m'`: Minute in hour (0-59)
15132 *   * `'ss'`: Second in minute, padded (00-59)
15133 *   * `'s'`: Second in minute (0-59)
15134 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
15135 *   * `'a'`: am/pm marker
15136 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
15137 *
15138 *   `format` string can also be one of the following predefined
15139 *   {@link guide/i18n localizable formats}:
15140 *
15141 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
15142 *     (e.g. Sep 3, 2010 12:05:08 pm)
15143 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
15144 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
15145 *     (e.g. Friday, September 3, 2010)
15146 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
15147 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
15148 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
15149 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
15150 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
15151 *
15152 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
15153 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
15154 *   (e.g. `"h 'o''clock'"`).
15155 *
15156 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
15157 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
15158 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
15159 *    specified in the string input, the time is considered to be in the local timezone.
15160 * @param {string=} format Formatting rules (see Description). If not specified,
15161 *    `mediumDate` is used.
15162 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
15163 *
15164 * @example
15165   <example>
15166     <file name="index.html">
15167       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
15168           <span>{{1288323623006 | date:'medium'}}</span><br>
15169       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
15170          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15171       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15172          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15173     </file>
15174     <file name="protractor.js" type="protractor">
15175       it('should format date', function() {
15176         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
15177            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
15178         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
15179            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15180         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15181            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15182       });
15183     </file>
15184   </example>
15185 */
15186dateFilter.$inject = ['$locale'];
15187function dateFilter($locale) {
15188
15189
15190  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
15191                     // 1        2       3         4          5          6          7          8  9     10      11
15192  function jsonStringToDate(string) {
15193    var match;
15194    if (match = string.match(R_ISO8601_STR)) {
15195      var date = new Date(0),
15196          tzHour = 0,
15197          tzMin  = 0,
15198          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
15199          timeSetter = match[8] ? date.setUTCHours : date.setHours;
15200
15201      if (match[9]) {
15202        tzHour = int(match[9] + match[10]);
15203        tzMin = int(match[9] + match[11]);
15204      }
15205      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
15206      var h = int(match[4]||0) - tzHour;
15207      var m = int(match[5]||0) - tzMin;
15208      var s = int(match[6]||0);
15209      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
15210      timeSetter.call(date, h, m, s, ms);
15211      return date;
15212    }
15213    return string;
15214  }
15215
15216
15217  return function(date, format) {
15218    var text = '',
15219        parts = [],
15220        fn, match;
15221
15222    format = format || 'mediumDate';
15223    format = $locale.DATETIME_FORMATS[format] || format;
15224    if (isString(date)) {
15225      date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
15226    }
15227
15228    if (isNumber(date)) {
15229      date = new Date(date);
15230    }
15231
15232    if (!isDate(date)) {
15233      return date;
15234    }
15235
15236    while(format) {
15237      match = DATE_FORMATS_SPLIT.exec(format);
15238      if (match) {
15239        parts = concat(parts, match, 1);
15240        format = parts.pop();
15241      } else {
15242        parts.push(format);
15243        format = null;
15244      }
15245    }
15246
15247    forEach(parts, function(value){
15248      fn = DATE_FORMATS[value];
15249      text += fn ? fn(date, $locale.DATETIME_FORMATS)
15250                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
15251    });
15252
15253    return text;
15254  };
15255}
15256
15257
15258/**
15259 * @ngdoc filter
15260 * @name json
15261 * @kind function
15262 *
15263 * @description
15264 *   Allows you to convert a JavaScript object into JSON string.
15265 *
15266 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
15267 *   the binding is automatically converted to JSON.
15268 *
15269 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
15270 * @returns {string} JSON string.
15271 *
15272 *
15273 * @example
15274   <example>
15275     <file name="index.html">
15276       <pre>{{ {'name':'value'} | json }}</pre>
15277     </file>
15278     <file name="protractor.js" type="protractor">
15279       it('should jsonify filtered objects', function() {
15280         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15281       });
15282     </file>
15283   </example>
15284 *
15285 */
15286function jsonFilter() {
15287  return function(object) {
15288    return toJson(object, true);
15289  };
15290}
15291
15292
15293/**
15294 * @ngdoc filter
15295 * @name lowercase
15296 * @kind function
15297 * @description
15298 * Converts string to lowercase.
15299 * @see angular.lowercase
15300 */
15301var lowercaseFilter = valueFn(lowercase);
15302
15303
15304/**
15305 * @ngdoc filter
15306 * @name uppercase
15307 * @kind function
15308 * @description
15309 * Converts string to uppercase.
15310 * @see angular.uppercase
15311 */
15312var uppercaseFilter = valueFn(uppercase);
15313
15314/**
15315 * @ngdoc filter
15316 * @name limitTo
15317 * @kind function
15318 *
15319 * @description
15320 * Creates a new array or string containing only a specified number of elements. The elements
15321 * are taken from either the beginning or the end of the source array or string, as specified by
15322 * the value and sign (positive or negative) of `limit`.
15323 *
15324 * @param {Array|string} input Source array or string to be limited.
15325 * @param {string|number} limit The length of the returned array or string. If the `limit` number
15326 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15327 *     If the number is negative, `limit` number  of items from the end of the source array/string
15328 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15329 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15330 *     had less than `limit` elements.
15331 *
15332 * @example
15333   <example module="limitToExample">
15334     <file name="index.html">
15335       <script>
15336         angular.module('limitToExample', [])
15337           .controller('ExampleController', ['$scope', function($scope) {
15338             $scope.numbers = [1,2,3,4,5,6,7,8,9];
15339             $scope.letters = "abcdefghi";
15340             $scope.numLimit = 3;
15341             $scope.letterLimit = 3;
15342           }]);
15343       </script>
15344       <div ng-controller="ExampleController">
15345         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
15346         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15347         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
15348         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15349       </div>
15350     </file>
15351     <file name="protractor.js" type="protractor">
15352       var numLimitInput = element(by.model('numLimit'));
15353       var letterLimitInput = element(by.model('letterLimit'));
15354       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15355       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15356
15357       it('should limit the number array to first three items', function() {
15358         expect(numLimitInput.getAttribute('value')).toBe('3');
15359         expect(letterLimitInput.getAttribute('value')).toBe('3');
15360         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15361         expect(limitedLetters.getText()).toEqual('Output letters: abc');
15362       });
15363
15364       it('should update the output when -3 is entered', function() {
15365         numLimitInput.clear();
15366         numLimitInput.sendKeys('-3');
15367         letterLimitInput.clear();
15368         letterLimitInput.sendKeys('-3');
15369         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15370         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15371       });
15372
15373       it('should not exceed the maximum size of input array', function() {
15374         numLimitInput.clear();
15375         numLimitInput.sendKeys('100');
15376         letterLimitInput.clear();
15377         letterLimitInput.sendKeys('100');
15378         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15379         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15380       });
15381     </file>
15382   </example>
15383 */
15384function limitToFilter(){
15385  return function(input, limit) {
15386    if (!isArray(input) && !isString(input)) return input;
15387
15388    if (Math.abs(Number(limit)) === Infinity) {
15389      limit = Number(limit);
15390    } else {
15391      limit = int(limit);
15392    }
15393
15394    if (isString(input)) {
15395      //NaN check on limit
15396      if (limit) {
15397        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
15398      } else {
15399        return "";
15400      }
15401    }
15402
15403    var out = [],
15404      i, n;
15405
15406    // if abs(limit) exceeds maximum length, trim it
15407    if (limit > input.length)
15408      limit = input.length;
15409    else if (limit < -input.length)
15410      limit = -input.length;
15411
15412    if (limit > 0) {
15413      i = 0;
15414      n = limit;
15415    } else {
15416      i = input.length + limit;
15417      n = input.length;
15418    }
15419
15420    for (; i<n; i++) {
15421      out.push(input[i]);
15422    }
15423
15424    return out;
15425  };
15426}
15427
15428/**
15429 * @ngdoc filter
15430 * @name orderBy
15431 * @kind function
15432 *
15433 * @description
15434 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
15435 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
15436 * correctly, make sure they are actually being saved as numbers and not strings.
15437 *
15438 * @param {Array} array The array to sort.
15439 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
15440 *    used by the comparator to determine the order of elements.
15441 *
15442 *    Can be one of:
15443 *
15444 *    - `function`: Getter function. The result of this function will be sorted using the
15445 *      `<`, `=`, `>` operator.
15446 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
15447 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
15448 *      ascending or descending sort order (for example, +name or -name).
15449 *    - `Array`: An array of function or string predicates. The first predicate in the array
15450 *      is used for sorting, but when two items are equivalent, the next predicate is used.
15451 *
15452 * @param {boolean=} reverse Reverse the order of the array.
15453 * @returns {Array} Sorted copy of the source array.
15454 *
15455 * @example
15456   <example module="orderByExample">
15457     <file name="index.html">
15458       <script>
15459         angular.module('orderByExample', [])
15460           .controller('ExampleController', ['$scope', function($scope) {
15461             $scope.friends =
15462                 [{name:'John', phone:'555-1212', age:10},
15463                  {name:'Mary', phone:'555-9876', age:19},
15464                  {name:'Mike', phone:'555-4321', age:21},
15465                  {name:'Adam', phone:'555-5678', age:35},
15466                  {name:'Julie', phone:'555-8765', age:29}];
15467             $scope.predicate = '-age';
15468           }]);
15469       </script>
15470       <div ng-controller="ExampleController">
15471         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15472         <hr/>
15473         [ <a href="" ng-click="predicate=''">unsorted</a> ]
15474         <table class="friend">
15475           <tr>
15476             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15477                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15478             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15479             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15480           </tr>
15481           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15482             <td>{{friend.name}}</td>
15483             <td>{{friend.phone}}</td>
15484             <td>{{friend.age}}</td>
15485           </tr>
15486         </table>
15487       </div>
15488     </file>
15489   </example>
15490 *
15491 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
15492 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
15493 * desired parameters.
15494 *
15495 * Example:
15496 *
15497 * @example
15498  <example module="orderByExample">
15499    <file name="index.html">
15500      <div ng-controller="ExampleController">
15501        <table class="friend">
15502          <tr>
15503            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
15504              (<a href="" ng-click="order('-name',false)">^</a>)</th>
15505            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
15506            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
15507          </tr>
15508          <tr ng-repeat="friend in friends">
15509            <td>{{friend.name}}</td>
15510            <td>{{friend.phone}}</td>
15511            <td>{{friend.age}}</td>
15512          </tr>
15513        </table>
15514      </div>
15515    </file>
15516
15517    <file name="script.js">
15518      angular.module('orderByExample', [])
15519        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
15520          var orderBy = $filter('orderBy');
15521          $scope.friends = [
15522            { name: 'John',    phone: '555-1212',    age: 10 },
15523            { name: 'Mary',    phone: '555-9876',    age: 19 },
15524            { name: 'Mike',    phone: '555-4321',    age: 21 },
15525            { name: 'Adam',    phone: '555-5678',    age: 35 },
15526            { name: 'Julie',   phone: '555-8765',    age: 29 }
15527          ];
15528          $scope.order = function(predicate, reverse) {
15529            $scope.friends = orderBy($scope.friends, predicate, reverse);
15530          };
15531          $scope.order('-age',false);
15532        }]);
15533    </file>
15534</example>
15535 */
15536orderByFilter.$inject = ['$parse'];
15537function orderByFilter($parse){
15538  return function(array, sortPredicate, reverseOrder) {
15539    if (!isArray(array)) return array;
15540    if (!sortPredicate) return array;
15541    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15542    sortPredicate = map(sortPredicate, function(predicate){
15543      var descending = false, get = predicate || identity;
15544      if (isString(predicate)) {
15545        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15546          descending = predicate.charAt(0) == '-';
15547          predicate = predicate.substring(1);
15548        }
15549        get = $parse(predicate);
15550        if (get.constant) {
15551          var key = get();
15552          return reverseComparator(function(a,b) {
15553            return compare(a[key], b[key]);
15554          }, descending);
15555        }
15556      }
15557      return reverseComparator(function(a,b){
15558        return compare(get(a),get(b));
15559      }, descending);
15560    });
15561    var arrayCopy = [];
15562    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
15563    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
15564
15565    function comparator(o1, o2){
15566      for ( var i = 0; i < sortPredicate.length; i++) {
15567        var comp = sortPredicate[i](o1, o2);
15568        if (comp !== 0) return comp;
15569      }
15570      return 0;
15571    }
15572    function reverseComparator(comp, descending) {
15573      return toBoolean(descending)
15574          ? function(a,b){return comp(b,a);}
15575          : comp;
15576    }
15577    function compare(v1, v2){
15578      var t1 = typeof v1;
15579      var t2 = typeof v2;
15580      if (t1 == t2) {
15581        if (isDate(v1) && isDate(v2)) {
15582          v1 = v1.valueOf();
15583          v2 = v2.valueOf();
15584        }
15585        if (t1 == "string") {
15586           v1 = v1.toLowerCase();
15587           v2 = v2.toLowerCase();
15588        }
15589        if (v1 === v2) return 0;
15590        return v1 < v2 ? -1 : 1;
15591      } else {
15592        return t1 < t2 ? -1 : 1;
15593      }
15594    }
15595  };
15596}
15597
15598function ngDirective(directive) {
15599  if (isFunction(directive)) {
15600    directive = {
15601      link: directive
15602    };
15603  }
15604  directive.restrict = directive.restrict || 'AC';
15605  return valueFn(directive);
15606}
15607
15608/**
15609 * @ngdoc directive
15610 * @name a
15611 * @restrict E
15612 *
15613 * @description
15614 * Modifies the default behavior of the html A tag so that the default action is prevented when
15615 * the href attribute is empty.
15616 *
15617 * This change permits the easy creation of action links with the `ngClick` directive
15618 * without changing the location or causing page reloads, e.g.:
15619 * `<a href="" ng-click="list.addItem()">Add Item</a>`
15620 */
15621var htmlAnchorDirective = valueFn({
15622  restrict: 'E',
15623  compile: function(element, attr) {
15624
15625    if (msie <= 8) {
15626
15627      // turn <a href ng-click="..">link</a> into a stylable link in IE
15628      // but only if it doesn't have name attribute, in which case it's an anchor
15629      if (!attr.href && !attr.name) {
15630        attr.$set('href', '');
15631      }
15632
15633      // add a comment node to anchors to workaround IE bug that causes element content to be reset
15634      // to new attribute content if attribute is updated with value containing @ and element also
15635      // contains value with @
15636      // see issue #1949
15637      element.append(document.createComment('IE fix'));
15638    }
15639
15640    if (!attr.href && !attr.xlinkHref && !attr.name) {
15641      return function(scope, element) {
15642        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15643        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15644                   'xlink:href' : 'href';
15645        element.on('click', function(event){
15646          // if we have no href url, then don't navigate anywhere.
15647          if (!element.attr(href)) {
15648            event.preventDefault();
15649          }
15650        });
15651      };
15652    }
15653  }
15654});
15655
15656/**
15657 * @ngdoc directive
15658 * @name ngHref
15659 * @restrict A
15660 * @priority 99
15661 *
15662 * @description
15663 * Using Angular markup like `{{hash}}` in an href attribute will
15664 * make the link go to the wrong URL if the user clicks it before
15665 * Angular has a chance to replace the `{{hash}}
15665` markup with its
15666 * value. Until Angular replaces the markup the link will be broken
15667 * and will most likely return a 404 error.
15668 *
15669 * The `ngHref` directive solves this problem.
15670 *
15671 * The wrong way to write it:
15672 * ```html
15673 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15674 * ```
15675 *
15676 * The correct way to write it:
15677 * ```html
15678 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15679 * ```
15680 *
15681 * @element A
15682 * @param {template} ngHref any string which can contain `{{}}` markup.
15683 *
15684 * @example
15685 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15686 * in links and their different behaviors:
15687    <example>
15688      <file name="index.html">
15689        <input ng-model="value" /><br />
15690        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15691        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15692        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15693        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15694        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15695        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15696      </file>
15697      <file name="protractor.js" type="protractor">
15698        it('should execute ng-click but not reload when href without value', function() {
15699          element(by.id('link-1')).click();
15700          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15701          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15702        });
15703
15704        it('should execute ng-click but not reload when href empty string', function() {
15705          element(by.id('link-2')).click();
15706          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15707          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15708        });
15709
15710        it('should execute ng-click and change url when ng-href specified', function() {
15711          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15712
15713          element(by.id('link-3')).click();
15714
15715          // At this point, we navigate away from an Angular page, so we need
15716          // to use browser.driver to get the base webdriver.
15717
15718          browser.wait(function() {
15719            return browser.driver.getCurrentUrl().then(function(url) {
15720              return url.match(/\/123$/);
15721            });
15722          }, 5000, 'page should navigate to /123');
15723        });
15724
15725        xit('should execute ng-click but not reload when href empty string and name specified', function() {
15726          element(by.id('link-4')).click();
15727          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15728          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15729        });
15730
15731        it('should execute ng-click but not reload when no href but name specified', function() {
15732          element(by.id('link-5')).click();
15733          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15734          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15735        });
15736
15737        it('should only change url when only ng-href', function() {
15738          element(by.model('value')).clear();
15739          element(by.model('value')).sendKeys('6');
15740          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15741
15742          element(by.id('link-6')).click();
15743
15744          // At this point, we navigate away from an Angular page, so we need
15745          // to use browser.driver to get the base webdriver.
15746          browser.wait(function() {
15747            return browser.driver.getCurrentUrl().then(function(url) {
15748              return url.match(/\/6$/);
15749            });
15750          }, 5000, 'page should navigate to /6');
15751        });
15752      </file>
15753    </example>
15754 */
15755
15756/**
15757 * @ngdoc directive
15758 * @name ngSrc
15759 * @restrict A
15760 * @priority 99
15761 *
15762 * @description
15763 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15764 * work right: The browser will fetch from the URL with the literal
15765 * text `{{hash}}` until Angular replaces the expression inside
15766 * `{{hash}}`. The `ngSrc` directive solves this problem.
15767 *
15768 * The buggy way to write it:
15769 * ```html
15770 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15771 * ```
15772 *
15773 * The correct way to write it:
15774 * ```html
15775 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15776 * ```
15777 *
15778 * @element IMG
15779 * @param {template} ngSrc any string which can contain `{{}}` markup.
15780 */
15781
15782/**
15783 * @ngdoc directive
15784 * @name ngSrcset
15785 * @restrict A
15786 * @priority 99
15787 *
15788 * @description
15789 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15790 * work right: The browser will fetch from the URL with the literal
15791 * text `{{hash}}` until Angular replaces the expression inside
15792 * `{{hash}}`. The `ngSrcset` directive solves this problem.
15793 *
15794 * The buggy way to write it:
15795 * ```html
15796 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15797 * ```
15798 *
15799 * The correct way to write it:
15800 * ```html
15801 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15802 * ```
15803 *
15804 * @element IMG
15805 * @param {template} ngSrcset any string which can contain `{{}}` markup.
15806 */
15807
15808/**
15809 * @ngdoc directive
15810 * @name ngDisabled
15811 * @restrict A
15812 * @priority 100
15813 *
15814 * @description
15815 *
15816 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15817 * ```html
15818 * <div ng-init="scope = { isDisabled: false }">
15819 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15820 * </div>
15821 * ```
15822 *
15823 * The HTML specification does not require browsers to preserve the values of boolean attributes
15824 * such as disabled. (Their presence means true and their absence means false.)
15825 * If we put an Angular interpolation expression into such an attribute then the
15826 * binding information would be lost when the browser removes the attribute.
15827 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15828 * This complementary directive is not removed by the browser and so provides
15829 * a permanent reliable place to store the binding information.
15830 *
15831 * @example
15832    <example>
15833      <file name="index.html">
15834        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15835        <button ng-model="button" ng-disabled="checked">Button</button>
15836      </file>
15837      <file name="protractor.js" type="protractor">
15838        it('should toggle button', function() {
15839          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
15840          element(by.model('checked')).click();
15841          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
15842        });
15843      </file>
15844    </example>
15845 *
15846 * @element INPUT
15847 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
15848 *     then special attribute "disabled" will be set on the element
15849 */
15850
15851
15852/**
15853 * @ngdoc directive
15854 * @name ngChecked
15855 * @restrict A
15856 * @priority 100
15857 *
15858 * @description
15859 * The HTML specification does not require browsers to preserve the values of boolean attributes
15860 * such as checked. (Their presence means true and their absence means false.)
15861 * If we put an Angular interpolation expression into such an attribute then the
15862 * binding information would be lost when the browser removes the attribute.
15863 * The `ngChecked` directive solves this problem for the `checked` attribute.
15864 * This complementary directive is not removed by the browser and so provides
15865 * a permanent reliable place to store the binding information.
15866 * @example
15867    <example>
15868      <file name="index.html">
15869        Check me to check both: <input type="checkbox" ng-model="master"><br/>
15870        <input id="checkSlave" type="checkbox" ng-checked="master">
15871      </file>
15872      <file name="protractor.js" type="protractor">
15873        it('should check both checkBoxes', function() {
15874          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15875          element(by.model('master')).click();
15876          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15877        });
15878      </file>
15879    </example>
15880 *
15881 * @element INPUT
15882 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
15883 *     then special attribute "checked" will be set on the element
15884 */
15885
15886
15887/**
15888 * @ngdoc directive
15889 * @name ngReadonly
15890 * @restrict A
15891 * @priority 100
15892 *
15893 * @description
15894 * The HTML specification does not require browsers to preserve the values of boolean attributes
15895 * such as readonly. (Their presence means true and their absence means false.)
15896 * If we put an Angular interpolation expression into such an attribute then the
15897 * binding information would be lost when the browser removes the attribute.
15898 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15899 * This complementary directive is not removed by the browser and so provides
15900 * a permanent reliable place to store the binding information.
15901 * @example
15902    <example>
15903      <file name="index.html">
15904        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15905        <input type="text" ng-readonly="checked" value="I'm Angular"/>
15906      </file>
15907      <file name="protractor.js" type="protractor">
15908        it('should toggle readonly attr', function() {
15909          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
15910          element(by.model('checked')).click();
15911          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
15912        });
15913      </file>
15914    </example>
15915 *
15916 * @element INPUT
15917 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
15918 *     then special attribute "readonly" will be set on the element
15919 */
15920
15921
15922/**
15923 * @ngdoc directive
15924 * @name ngSelected
15925 * @restrict A
15926 * @priority 100
15927 *
15928 * @description
15929 * The HTML specification does not require browsers to preserve the values of boolean attributes
15930 * such as selected. (Their presence means true and their absence means false.)
15931 * If we put an Angular interpolation expression into such an attribute then the
15932 * binding information would be lost when the browser removes the attribute.
15933 * The `ngSelected` directive solves this problem for the `selected` attribute.
15934 * This complementary directive is not removed by the browser and so provides
15935 * a permanent reliable place to store the binding information.
15936 *
15937 * @example
15938    <example>
15939      <file name="index.html">
15940        Check me to select: <input type="checkbox" ng-model="selected"><br/>
15941        <select>
15942          <option>Hello!</option>
15943          <option id="greet" ng-selected="selected">Greetings!</option>
15944        </select>
15945      </file>
15946      <file name="protractor.js" type="protractor">
15947        it('should select Greetings!', function() {
15948          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15949          element(by.model('selected')).click();
15950          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15951        });
15952      </file>
15953    </example>
15954 *
15955 * @element OPTION
15956 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
15957 *     then special attribute "selected" will be set on the element
15958 */
15959
15960/**
15961 * @ngdoc directive
15962 * @name ngOpen
15963 * @restrict A
15964 * @priority 100
15965 *
15966 * @description
15967 * The HTML specification does not require browsers to preserve the values of boolean attributes
15968 * such as open. (Their presence means true and their absence means false.)
15969 * If we put an Angular interpolation expression into such an attribute then the
15970 * binding information would be lost when the browser removes the attribute.
15971 * The `ngOpen` directive solves this problem for the `open` attribute.
15972 * This complementary directive is not removed by the browser and so provides
15973 * a permanent reliable place to store the binding information.
15974 * @example
15975     <example>
15976       <file name="index.html">
15977         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15978         <details id="details" ng-open="open">
15979            <summary>Show/Hide me</summary>
15980         </details>
15981       </file>
15982       <file name="protractor.js" type="protractor">
15983         it('should toggle open', function() {
15984           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15985           element(by.model('open')).click();
15986           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15987         });
15988       </file>
15989     </example>
15990 *
15991 * @element DETAILS
15992 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
15993 *     then special attribute "open" will be set on the element
15994 */
15995
15996var ngAttributeAliasDirectives = {};
15997
15998
15999// boolean attrs are evaluated
16000forEach(BOOLEAN_ATTR, function(propName, attrName) {
16001  // binding to multiple is not supported
16002  if (propName == "multiple") return;
16003
16004  var normalized = directiveNormalize('ng-' + attrName);
16005  ngAttributeAliasDirectives[normalized] = function() {
16006    return {
16007      priority: 100,
16008      link: function(scope, element, attr) {
16009        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
16010          attr.$set(attrName, !!value);
16011        });
16012      }
16013    };
16014  };
16015});
16016
16017
16018// ng-src, ng-srcset, ng-href are interpolated
16019forEach(['src', 'srcset', 'href'], function(attrName) {
16020  var normalized = directiveNormalize('ng-' + attrName);
16021  ngAttributeAliasDirectives[normalized] = function() {
16022    return {
16023      priority: 99, // it needs to run after the attributes are interpolated
16024      link: function(scope, element, attr) {
16025        var propName = attrName,
16026            name = attrName;
16027
16028        if (attrName === 'href' &&
16029            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
16030          name = 'xlinkHref';
16031          attr.$attr[name] = 'xlink:href';
16032          propName = null;
16033        }
16034
16035        attr.$observe(normalized, function(value) {
16036          if (!value)
16037             return;
16038
16039          attr.$set(name, value);
16040
16041          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
16042          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
16043          // to set the property as well to achieve the desired effect.
16044          // we use attr[attrName] value since $set can sanitize the url.
16045          if (msie && propName) element.prop(propName, attr[name]);
16046        });
16047      }
16048    };
16049  };
16050});
16051
16052/* global -nullFormCtrl */
16053var nullFormCtrl = {
16054  $addControl: noop,
16055  $removeControl: noop,
16056  $setValidity: noop,
16057  $setDirty: noop,
16058  $setPristine: noop
16059};
16060
16061/**
16062 * @ngdoc type
16063 * @name form.FormController
16064 *
16065 * @property {boolean} $pristine True if user has not interacted with the form yet.
16066 * @property {boolean} $dirty True if user has already interacted with the form.
16067 * @property {boolean} $valid True if all of the containing forms and controls are valid.
16068 * @property {boolean} $invalid True if at least one containing control or form is invali
16068d.
16069 *
16070 * @property {Object} $error Is an object hash, containing references to all invalid controls or
16071 *  forms, where:
16072 *
16073 *  - keys are validation tokens (error names),
16074 *  - values are arrays of controls or forms that are invalid for given error name.
16075 *
16076 *
16077 *  Built-in validation tokens:
16078 *
16079 *  - `email`
16080 *  - `max`
16081 *  - `maxlength`
16082 *  - `min`
16083 *  - `minlength`
16084 *  - `number`
16085 *  - `pattern`
16086 *  - `required`
16087 *  - `url`
16088 *
16089 * @description
16090 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
16091 * such as being valid/invalid or dirty/pristine.
16092 *
16093 * Each {@link ng.directive:form form} directive creates an instance
16094 * of `FormController`.
16095 *
16096 */
16097//asks for $scope to fool the BC controller module
16098FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
16099function FormController(element, attrs, $scope, $animate) {
16100  var form = this,
16101      parentForm = element.parent().controller('form') || nullFormCtrl,
16102      invalidCount = 0, // used to easily determine if we are valid
16103      errors = form.$error = {},
16104      controls = [];
16105
16106  // init state
16107  form.$name = attrs.name || attrs.ngForm;
16108  form.$dirty = false;
16109  form.$pristine = true;
16110  form.$valid = true;
16111  form.$invalid = false;
16112
16113  parentForm.$addControl(form);
16114
16115  // Setup initial state of the control
16116  element.addClass(PRISTINE_CLASS);
16117  toggleValidCss(true);
16118
16119  // convenience method for easy toggling of classes
16120  function toggleValidCss(isValid, validationErrorKey) {
16121    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16122    $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16123    $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
16124  }
16125
16126  /**
16127   * @ngdoc method
16128   * @name form.FormController#$addControl
16129   *
16130   * @description
16131   * Register a control with the form.
16132   *
16133   * Input elements using ngModelController do this automatically when they are linked.
16134   */
16135  form.$addControl = function(control) {
16136    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
16137    // and not added to the scope.  Now we throw an error.
16138    assertNotHasOwnProperty(control.$name, 'input');
16139    controls.push(control);
16140
16141    if (control.$name) {
16142      form[control.$name] = control;
16143    }
16144  };
16145
16146  /**
16147   * @ngdoc method
16148   * @name form.FormController#$removeControl
16149   *
16150   * @description
16151   * Deregister a control from the form.
16152   *
16153   * Input elements using ngModelController do this automatically when they are destroyed.
16154   */
16155  form.$removeControl = function(control) {
16156    if (control.$name && form[control.$name] === control) {
16157      delete form[control.$name];
16158    }
16159    forEach(errors, function(queue, validationToken) {
16160      form.$setValidity(validationToken, true, control);
16161    });
16162
16163    arrayRemove(controls, control);
16164  };
16165
16166  /**
16167   * @ngdoc method
16168   * @name form.FormController#$setValidity
16169   *
16170   * @description
16171   * Sets the validity of a form control.
16172   *
16173   * This method will also propagate to parent forms.
16174   */
16175  form.$setValidity = function(validationToken, isValid, control) {
16176    var queue = errors[validationToken];
16177
16178    if (isValid) {
16179      if (queue) {
16180        arrayRemove(queue, control);
16181        if (!queue.length) {
16182          invalidCount--;
16183          if (!invalidCount) {
16184            toggleValidCss(isValid);
16185            form.$valid = true;
16186            form.$invalid = false;
16187          }
16188          errors[validationToken] = false;
16189          toggleValidCss(true, validationToken);
16190          parentForm.$setValidity(validationToken, true, form);
16191        }
16192      }
16193
16194    } else {
16195      if (!invalidCount) {
16196        toggleValidCss(isValid);
16197      }
16198      if (queue) {
16199        if (includes(queue, control)) return;
16200      } else {
16201        errors[validationToken] = queue = [];
16202        invalidCount++;
16203        toggleValidCss(false, validationToken);
16204        parentForm.$setValidity(validationToken, false, form);
16205      }
16206      queue.push(control);
16207
16208      form.$valid = false;
16209      form.$invalid = true;
16210    }
16211  };
16212
16213  /**
16214   * @ngdoc method
16215   * @name form.FormController#$setDirty
16216   *
16217   * @description
16218   * Sets the form to a dirty state.
16219   *
16220   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
16221   * state (ng-dirty class). This method will also propagate to parent forms.
16222   */
16223  form.$setDirty = function() {
16224    $animate.removeClass(element, PRISTINE_CLASS);
16225    $animate.addClass(element, DIRTY_CLASS);
16226    form.$dirty = true;
16227    form.$pristine = false;
16228    parentForm.$setDirty();
16229  };
16230
16231  /**
16232   * @ngdoc method
16233   * @name form.FormController#$setPristine
16234   *
16235   * @description
16236   * Sets the form to its pristine state.
16237   *
16238   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
16239   * state (ng-pristine class). This method will also propagate to all the controls contained
16240   * in this form.
16241   *
16242   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
16243   * saving or resetting it.
16244   */
16245  form.$setPristine = function () {
16246    $animate.removeClass(element, DIRTY_CLASS);
16247    $animate.addClass(element, PRISTINE_CLASS);
16248    form.$dirty = false;
16249    form.$pristine = true;
16250    forEach(controls, function(control) {
16251      control.$setPristine();
16252    });
16253  };
16254}
16255
16256
16257/**
16258 * @ngdoc directive
16259 * @name ngForm
16260 * @restrict EAC
16261 *
16262 * @description
16263 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
16264 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
16265 * sub-group of controls needs to be determined.
16266 *
16267 * Note: the purpose of `ngForm` is to group controls,
16268 * but not to be a replacement for the `<form>` tag with all of its capabilities
16269 * (e.g. posting to the server, ...).
16270 *
16271 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
16272 *                       related scope, under this name.
16273 *
16274 */
16275
16276 /**
16277 * @ngdoc directive
16278 * @name form
16279 * @restrict E
16280 *
16281 * @description
16282 * Directive that instantiates
16283 * {@link form.FormController FormController}.
16284 *
16285 * If the `name` attribute is specified, the form controller is published onto the current scope under
16286 * this name.
16287 *
16288 * # Alias: {@link ng.directive:ngForm `ngForm`}
16289 *
16290 * In Angular forms can be nested. This means that the outer form is valid when all of the child
16291 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
16292 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
16293 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
16294 * using Angular validation directives in forms that are dynamically generated using the
16295 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
16296 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
16297 * `ngForm` directive and nest these in an outer `form` element.
16298 *
16299 *
16300 * # CSS classes
16301 *  - `ng-valid` is set if the form is valid.
16302 *  - `ng-invalid` is set if the form is invalid.
16303 *  - `ng-pristine` is set if the form is pristine.
16304 *  - `ng-dirty` is set if the form is dirty.
16305 *
16306 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
16307 *
16308 *
16309 * # Submitting a form and preventing the default action
16310 *
16311 * Since the role of forms in client-side Angular applications is different than in classical
16312 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
16313 * page reload that sends the data to the server. Instead some javascript logic should be triggered
16314 * to handle the form submission in an application-specific way.
16315 *
16316 * For this reason, Angular prevents the default action (form submission to the server) unless the
16317 * `<form>` element has an `action` attribute specified.
16318 *
16319 * You can use one of the following two ways to specify what javascript method should be called when
16320 * a form is submitted:
16321 *
16322 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
16323 * - {@link ng.directive:ngClick ngClick} directive on the first
16324  *  button or input field of type submit (input[type=submit])
16325 *
16326 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
16327 * or {@link ng.directive:ngClick ngClick} directives.
16328 * This is because of the following form submission rules in the HTML specification:
16329 *
16330 * - If a form has only one input field then hitting enter in this field triggers form submit
16331 * (`ngSubmit`)
16332 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
16333 * doesn't trigger submit
16334 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16335 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16336 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16337 *
16338 * @param {string=} name Name of the form. If specified, the form controller will be published into
16339 *                       related scope, under this name.
16340 *
16341 * ## Animation Hooks
16342 *
16343 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16344 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16345 * other validations that are performed within the form. Animations in ngForm are similar to how
16346 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16347 * as JS animations.
16348 *
16349 * The following example shows a simple way to utilize CSS transitions to style a form element
16350 * that has been rendered as invalid after it has been validated:
16351 *
16352 * <pre>
16353 * //be sure to include ngAnimate as a module to hook into more
16354 * //advanced animations
16355 * .my-form {
16356 *   transition:0.5s linear all;
16357 *   background: white;
16358 * }
16359 * .my-form.ng-invalid {
16360 *   background: red;
16361 *   color:white;
16362 * }
16363 * </pre>
16364 *
16365 * @example
16366    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
16367      <file name="index.html">
16368       <script>
16369         angular.module('formExample', [])
16370           .controller('FormController', ['$scope', function($scope) {
16371             $scope.userType = 'guest';
16372           }]);
16373       </script>
16374       <style>
16375        .my-form {
16376          -webkit-transition:all linear 0.5s;
16377          transition:all linear 0.5s;
16378          background: transparent;
16379        }
16380        .my-form.ng-invalid {
16381          background: red;
16382        }
16383       </style>
16384       <form name="myForm" ng-controller="FormController" class="my-form">
16385         userType: <input name="input" ng-model="userType" required>
16386         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16387         <tt>userType = {{userType}}</tt><br>
16388         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16389         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16390         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16391         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16392        </form>
16393      </file>
16394      <file name="protractor.js" type="protractor">
16395        it('should initialize to model', function() {
16396          var userType = element(by.binding('userType'));
16397          var valid = element(by.binding('myForm.input.$valid'));
16398
16399          expect(userType.getText()).toContain('guest');
16400          expect(valid.getText()).toContain('true');
16401        });
16402
16403        it('should be invalid if empty', function() {
16404          var userType = element(by.binding('userType'));
16405          var valid = element(by.binding('myForm.input.$valid'));
16406          var userInput = element(by.model('userType'));
16407
16408          userInput.clear();
16409          userInput.sendKeys('');
16410
16411          expect(userType.getText()).toEqual('userType =');
16412          expect(valid.getText()).toContain('false');
16413        });
16414      </file>
16415    </example>
16416 *
16417 */
16418var formDirectiveFactory = function(isNgForm) {
16419  return ['$timeout', function($timeout) {
16420    var formDirective = {
16421      name: 'form',
16422      restrict: isNgForm ? 'EAC' : 'E',
16423      controller: FormController,
16424      compile: function() {
16425        return {
16426          pre: function(scope, formElement, attr, controller) {
16427            if (!attr.action) {
16428              // we can't use jq events because if a form is destroyed during submission the default
16429              // action is not prevented. see #1238
16430              //
16431              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16432              // page reload if the form was destroyed by submission of the form via a click handler
16433              // on a button in the form. Looks like an IE9 specific bug.
16434              var preventDefaultListener = function(event) {
16435                event.preventDefault
16436                  ? event.preventDefault()
16437                  : event.returnValue = false; // IE
16438              };
16439
16440              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16441
16442              // unregister the preventDefault listener so that we don't not leak memory but in a
16443              // way that will achieve the prevention of the default action.
16444              formElement.on('$destroy', function() {
16445                $timeout(function() {
16446                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16447                }, 0, false);
16448              });
16449            }
16450
16451            var parentFormCtrl = formElement.parent().controller('form'),
16452                alias = attr.name || attr.ngForm;
16453
16454            if (alias) {
16455              setter(scope, alias, controller, alias);
16456            }
16457            if (parentFormCtrl) {
16458              formElement.on('$destroy', function() {
16459                parentFormCtrl.$removeControl(controller);
16460                if (alias) {
16461                  setter(scope, alias, undefined, alias);
16462                }
16463                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16464              });
16465            }
16466          }
16467        };
16468      }
16469    };
16470
16471    return formDirective;
16472  }];
16473};
16474
16475var formDirective = formDirectiveFactory();
16476var ngFormDirective = formDirectiveFactory(true);
16477
16478/* global VALID_CLASS: true,
16479    INVALID_CLASS: true,
16480    PRISTINE_CLASS: true,
16481    DIRTY_CLASS: true
16482*/
16483
16484var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16485var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
16486var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16487
16488var inputType = {
16489
16490  /**
16491   * @ngdoc input
16492   * @name input[text]
16493   *
16494   * @description
16495   * Standard HTML text input with angular data binding.
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=} required Adds `required` validation error key if the value is not entered.
16500   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16501   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16502   *    `required` when you want to data-bind to the `required` attribute.
16503   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16504   *    minlength.
16505   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16506   *    maxlength.
16507   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16508   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16509   *    patterns defined as scope expressions.
16510   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16511   *    interaction with the input element.
16512   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16513   *
16514   * @example
16515      <example name="text-input-directive" module="textInputExample">
16516        <file name="index.html">
16517         <script>
16518           angular.module('textInputExample', [])
16519             .controller('ExampleController', ['$scope', function($scope) {
16520               $scope.text = 'guest';
16521               $scope.word = /^\s*\w*\s*$/;
16522             }]);
16523         </script>
16524         <form name="myForm" ng-controller="ExampleController">
16525           Single word: <input type="text" name="input" ng-model="text"
16526                               ng-pattern="word" required ng-trim="false">
16527           <span class="error" ng-show="myForm.input.$error.required">
16528             Required!</span>
16529           <span class="error" ng-show="myForm.input.$error.pattern">
16530             Single word only!</span>
16531
16532           <tt>text = {{text}}</tt><br/>
16533           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16534           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16535           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16536           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16537          </form>
16538        </file>
16539        <file name="protractor.js" type="protractor">
16540          var text = element(by.binding('text'));
16541          var valid = element(by.binding('myForm.input.$valid'));
16542          var input = element(by.model('text'));
16543
16544          it('should initialize to model', function() {
16545            expect(text.getText()).toContain('guest');
16546            expect(valid.getText()).toContain('true');
16547          });
16548
16549          it('should be invalid if empty', function() {
16550            input.clear();
16551            input.sendKeys('');
16552
16553            expect(text.getText()).toEqual('text =');
16554            expect(valid.getText()).toContain('false');
16555          });
16556
16557          it('should be invalid if multi word', function() {
16558            input.clear();
16559            input.sendKeys('hello world');
16560
16561            expect(valid.getText()).toContain('false');
16562          });
16563        </file>
16564      </example>
16565   */
16566  'text': textInputType,
16567
16568
16569  /**
16570   * @ngdoc input
16571   * @name input[number]
16572   *
16573   * @description
16574   * Text input with number validation and transformation. Sets the `number` validation
16575   * error if not a valid number.
16576   *
16577   * @param {string} ngModel Assignable angular expression to data-bind to.
16578   * @param {string=} name Property name of the form under which the control is published.
16579   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16580   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16581   * @param {string=} required Sets `required` validation error key if the value is not entered.
16582   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16583   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16584   *    `required` when you want to data-bind to the `required` attribute.
16585   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16586   *    minlength.
16587   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16588   *    maxlength.
16589   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16590   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16591   *    patterns defined as scope expressions.
16592   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16593   *    interaction with the input element.
16594   *
16595   * @example
16596      <example name="number-input-directive" module="numberExample">
16597        <file name="index.html">
16598         <script>
16599           angular.module('numberExample', [])
16600             .controller('ExampleController', ['$scope', function($scope) {
16601               $scope.value = 12;
16602             }]);
16603         </script>
16604         <form name="myForm" ng-controller="ExampleController">
16605           Number: <input type="number" name="input" ng-model="value"
16606                          min="0" max="99" required>
16607           <span class="error" ng-show="myForm.input.$error.required">
16608             Required!</span>
16609           <span class="error" ng-show="myForm.input.$error.number">
16610             Not valid number!</span>
16611           <tt>value = {{value}}</tt><br/>
16612           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16613           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16614           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16615           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16616          </form>
16617        </file>
16618        <file name="protractor.js" type="protractor">
16619          var value = element(by.binding('value'));
16620          var valid = element(by.binding('myForm.input.$valid'));
16621          var input = element(by.model('value'));
16622
16623          it('should initialize to model', function() {
16624            expect(value.getText()).toContain('12');
16625            expect(valid.getText()).toContain('true');
16626          });
16627
16628          it('should be invalid if empty', function() {
16629            input.clear();
16630            input.sendKeys('');
16631            expect(value.getText()).toEqual('value =');
16632            expect(valid.getText()).toContain('false');
16633          });
16634
16635          it('should be invalid if over max', function() {
16636            input.clear();
16637            input.sendKeys('123');
16638            expect(value.getText()).toEqual('value =');
16639            expect(valid.getText()).toContain('false');
16640          });
16641        </file>
16642      </example>
16643   */
16644  'number': numberInputType,
16645
16646
16647  /**
16648   * @ngdoc input
16649   * @name input[url]
16650   *
16651   * @description
16652   * Text input with URL validation. Sets the `url` validation error key if the content is not a
16653   * valid URL.
16654   *
16655   * @param {string} ngModel Assignable angular expression to data-bind to.
16656   * @param {string=} name Property name of the form under which the control is published.
16657   * @param {string=} required Sets `required` validation error key if the value is not entered.
16658   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16659   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16660   *    `required` when you want to data-bind to the `required` attribute.
16661   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16662   *    minlength.
16663   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16664   *    maxlength.
16665   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16666   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16667   *    patterns defined as scope expressions.
16668   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16669   *    interaction with the input element.
16670   *
16671   * @example
16672      <example name="url-input-directive" module="urlExample">
16673        <file name="index.html">
16674         <script>
16675           angular.module('urlExample', [])
16676             .controller('ExampleController', ['$scope', function($scope) {
16677               $scope.text = 'http://google.com';
16678             }]);
16679         </script>
16680         <form name="myForm" ng-controller="ExampleController">
16681           URL: <input type="url" name="input" ng-model="text" required>
16682           <span class="error" ng-show="myForm.input.$error.required">
16683             Required!</span>
16684           <span class="error" ng-show="myForm.input.$error.url">
16685             Not valid url!</span>
16686           <tt>text = {{text}}</tt><br/>
16687           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16688           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16689           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16690           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16691           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16692          </form>
16693        </file>
16694        <file name="protractor.js" type="protractor">
16695          var text = element(by.binding('text'));
16696          var valid = element(by.binding('myForm.input.$valid'));
16697          var input = element(by.model('text'));
16698
16699          it('should initialize to model', function() {
16700            expect(text.getText()).toContain('http://google.com');
16701            expect(valid.getText()).toContain('true');
16702          });
16703
16704          it('should be invalid if empty', function() {
16705            input.clear();
16706            input.sendKeys('');
16707
16708            expect(text.getText()).toEqual('text =');
16709            expect(valid.getText()).toContain('false');
16710          });
16711
16712          it('should be invalid if not url', function() {
16713            input.clear();
16714            input.sendKeys('box');
16715
16716            expect(valid.getText()).toContain('false');
16717          });
16718        </file>
16719      </example>
16720   */
16721  'url': urlInputType,
16722
16723
16724  /**
16725   * @ngdoc input
16726   * @name input[email]
16727   *
16728   * @description
16729   * Text input with email validation. Sets the `email` validation error key if not a valid email
16730   * address.
16731   *
16732   * @param {string} ngModel Assignable angular expression to data-bind to.
16733   * @param {string=} name Property name of the form under which the control is published.
16734   * @param {string=} required Sets `required` validation error key if the value is not entered.
16735   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16736   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16737   *    `required` when you want to data-bind to the `required` attribute.
16738   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16739   *    minlength.
16740   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16741   *    maxlength.
16742   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16743   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16744   *    patterns defined as scope expressions.
16745   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16746   *    interaction with the input element.
16747   *
16748   * @example
16749      <example name="email-input-directive" module="emailExample">
16750        <file name="index.html">
16751         <script>
16752           angular.module('emailExample', [])
16753             .controller('ExampleController', ['$scope', function($scope) {
16754               $scope.text = '[email protected]';
16755             }]);
16756         </script>
16757           <form name="myForm" ng-controller="ExampleController">
16758             Email: <input type="email" name="input" ng-model="text" required>
16759             <span class="error" ng-show="myForm.input.$error.required">
16760               Required!</span>
16761             <span class="error" ng-show="myForm.input.$error.email">
16762               Not valid email!</span>
16763             <tt>text = {{text}}</tt><br/>
16764             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16765             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16766             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16767             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16768             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16769           </form>
16770         </file>
16771        <file name="protractor.js" type="protractor">
16772          var text = element(by.binding('text'));
16773          var valid = element(by.binding('myForm.input.$valid'));
16774          var input = element(by.model('text'));
16775
16776          it('should initialize to model', function() {
16777            expect(text.getText()).toContain('[email protected]');
16778            expect(valid.getText()).toContain('true');
16779          });
16780
16781          it('should be invalid if empty', function() {
16782            input.clear();
16783            input.sendKeys('');
16784            expect(text.getText()).toEqual('text =');
16785            expect(valid.getText()).toContain('false');
16786          });
16787
16788          it('should be invalid if not email', function() {
16789            input.clear();
16790            input.sendKeys('xxx');
16791
16792            expect(valid.getText()).toContain('false');
16793          });
16794        </file>
16795      </example>
16796   */
16797  'email': emailInputType,
16798
16799
16800  /**
16801   * @ngdoc input
16802   * @name input[radio]
16803   *
16804   * @description
16805   * HTML radio button.
16806   *
16807   * @param {string} ngModel Assignable angular expression to data-bind to.
16808   * @param {string} value The value to which the expression should be set when selected.
16809   * @param {string=} name Property name of the form under which the control is published.
16810   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16811   *    interaction with the input element.
16812   * @param {string} ngValue Angular expression which sets the value to which the expression should
16813   *    be set when selected.
16814   *
16815   * @example
16816      <example name="radio-input-directive" module="radioExample">
16817        <file name="index.html">
16818         <script>
16819           angular.module('radioExample', [])
16820             .controller('ExampleController', ['$scope', function($scope) {
16821               $scope.color = 'blue';
16822               $scope.specialValue = {
16823                 "id": "12345",
16824                 "value": "green"
16825               };
16826             }]);
16827         </script>
16828         <form name="myForm" ng-controller="ExampleController">
16829           <input type="radio" ng-model="color" value="red">  Red <br/>
16830           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16831           <input type="radio" ng-model="color" value="blue"> Blue <br/>
16832           <tt>color = {{color | json}}</tt><br/>
16833          </form>
16834          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16835        </file>
16836        <file name="protractor.js" type="protractor">
16837          it('should change state', function() {
16838            var color = element(by.binding('color'));
16839
16840            expect(color.getText()).toContain('blue');
16841
16842            element.all(by.model('color')).get(0).click();
16843
16844            expect(color.getText()).toContain('red');
16845          });
16846        </file>
16847      </example>
16848   */
16849  'radio': radioInputType,
16850
16851
16852  /**
16853   * @ngdoc input
16854   * @name input[checkbox]
16855   *
16856   * @description
16857   * HTML checkbox.
16858   *
16859   * @param {string} ngModel Assignable angular expression to data-bind to.
16860   * @param {string=} name Property name of the form under which the control is published.
16861   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16862   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16863   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16864   *    interaction with the input element.
16865   *
16866   * @example
16867      <example name="checkbox-input-directive" module="checkboxExample">
16868        <file name="index.html">
16869         <script>
16870           angular.module('checkboxExample', [])
16871             .controller('ExampleController', ['$scope', function($scope) {
16872               $scope.value1 = true;
16873               $scope.value2 = 'YES'
16874             }]);
16875         </script>
16876         <form name="myForm" ng-controller="ExampleController">
16877           Value1: <input type="checkbox" ng-model="value1"> <br/>
16878           Value2: <input type="checkbox" ng-model="value2"
16879                          ng-true-value="YES" ng-false-value="NO"> <br/>
16880           <tt>value1 = {{value1}}</tt><br/>
16881           <tt>value2 = {{value2}}</tt><br/>
16882          </form>
16883        </file>
16884        <file name="protractor.js" type="protractor">
16885          it('should change state', function() {
16886            var value1 = element(by.binding('value1'));
16887            var value2 = element(by.binding('value2'));
16888
16889            expect(value1.getText()).toContain('true');
16890            expect(value2.getText()).toContain('YES');
16891
16892            element(by.model('value1')).click();
16893            element(by.model('value2')).click();
16894
16895            expect(value1.getText()).toContain('false');
16896            expect(value2.getText()).toContain('NO');
16897          });
16898        </file>
16899      </example>
16900   */
16901  'checkbox': checkboxInputType,
16902
16903  'hidden': noop,
16904  'button': noop,
16905  'submit': noop,
16906  'reset': noop,
16907  'file': noop
16908};
16909
16910// A helper function to call $setValidity and return the value / undefined,
16911// a pattern that is repeated a lot in the input validation logic.
16912function validate(ctrl, validatorName, validity, value){
16913  ctrl.$setValidity(validatorName, validity);
16914  return validity ? value : undefined;
16915}
16916
16917function testFlags(validity, flags) {
16918  var i, flag;
16919  if (flags) {
16920    for (i=0; i<flags.length; ++i) {
16921      flag = flags[i];
16922      if (validity[flag]) {
16923        return true;
16924      }
16925    }
16926  }
16927  return false;
16928}
16929
16930// Pass validity so that behaviour can be mocked easier.
16931function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
16932  if (isObject(validity)) {
16933    ctrl.$$hasNativeValidators = true;
16934    var validator = function(value) {
16935      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
16936      // perform the required validation)
16937      if (!ctrl.$error[validatorName] &&
16938          !testFlags(validity, ignoreFlags) &&
16939          testFlags(validity, badFlags)) {
16940        ctrl.$setValidity(validatorName, false);
16941        return;
16942      }
16943      return value;
16944    };
16945    ctrl.$parsers.push(validator);
16946  }
16947}
16948
16949function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16950  var validity = element.prop(VALIDITY_STATE_PROPERTY);
16951  var placeholder = element[0].placeholder, noevent = {};
16952  ctrl.$$validityState = validity;
16953
16954  // In composition mode, users are still inputing intermediate text buffer,
16955  // hold the listener until composition is done.
16956  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16957  if (!$sniffer.android) {
16958    var composing = false;
16959
16960    element.on('compositionstart', function(data) {
16961      composing = true;
16962    });
16963
16964    element.on('compositionend', function() {
16965      composing = false;
16966      listener();
16967    });
16968  }
16969
16970  var listener = function(ev) {
16971    if (composing) return;
16972    var value = element.val();
16973
16974    // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
16975    // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
16976    // IE also sends input events for other non-input-related things, (such as focusing on a
16977    // form control), so this change is not entirely enough to solve this.
16978    if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
16979      placeholder = element[0].placeholder;
16980      return;
16981    }
16982
16983    // By default we will trim the value
16984    // If the attribute ng-trim exists we will avoid trimming
16985    // e.g. <input ng-model="foo" ng-trim="false">
16986    if (toBoolean(attr.ngTrim || 'T')) {
16987      value = trim(value);
16988    }
16989
16990    // If a control is suffering from bad input, browsers discard its value, so it may be
16991    // necessary to revalidate even if the control's value is the same empty value twice in
16992    // a row.
16993    var revalidate = validity && ctrl.$$hasNativeValidators;
16994    if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
16995      if (scope.$$phase) {
16996        ctrl.$setViewValue(value);
16997      } else {
16998        scope.$apply(function() {
16999          ctrl.$setViewValue(value);
17000        });
17001      }
17002    }
17003  };
17004
17005  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
17006  // input event on backspace, delete or cut
17007  if ($sniffer.hasEvent('input')) {
17008    element.on('input', listener);
17009  } else {
17010    var timeout;
17011
17012    var deferListener = function() {
17013      if (!timeout) {
17014        timeout = $browser.defer(function() {
17015          listener();
17016          timeout = null;
17017        });
17018      }
17019    };
17020
17021    element.on('keydown', function(event) {
17022      var key = event.keyCode;
17023
17024      // ignore
17025      //    command            modifiers                   arrows
17026      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
17027
17028      deferListener();
17029    });
17030
17031    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
17032    if ($sniffer.hasEvent('paste')) {
17033      element.on('paste cut', deferListener);
17034    }
17035  }
17036
17037  // if user paste into input using mouse on older browser
17038  // or form autocomplete on newer browser, we need "change" event to catch it
17039  element.on('change', listener);
17040
17041  ctrl.$render = function() {
17042    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
17043  };
17044
17045  // pattern validator
17046  var pattern = attr.ngPattern,
17047      patternValidator,
17048      match;
17049
17050  if (pattern) {
17051    var validateRegex = function(regexp, value) {
17052      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
17053    };
17054    match = pattern.match(/^\/(.*)\/([gim]*)$/);
17055    if (match) {
17056      pattern = new RegExp(match[1], match[2]);
17057      patternValidator = function(value) {
17058        return validateRegex(pattern, value);
17059      };
17060    } else {
17061      patternValidator = function(value) {
17062        var patternObj = scope.$eval(pattern);
17063
17064        if (!patternObj || !patternObj.test) {
17065          throw minErr('ngPattern')('noregexp',
17066            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
17067            patternObj, startingTag(element));
17068        }
17069        return validateRegex(patternObj, value);
17070      };
17071    }
17072
17073    ctrl.$formatters.push(patternValidator);
17074    ctrl.$parsers.push(patternValidator);
17075  }
17076
17077  // min length validator
17078  if (attr.ngMinlength) {
17079    var minlength = int(attr.ngMinlength);
17080    var minLengthValidator = function(value) {
17081      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
17082    };
17083
17084    ctrl.$parsers.push(minLengthValidator);
17085    ctrl.$formatters.push(minLengthValidator);
17086  }
17087
17088  // max length validator
17089  if (attr.ngMaxlength) {
17090    var maxlength = int(attr.ngMaxlength);
17091    var maxLengthValidator = function(value) {
17092      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
17093    };
17094
17095    ctrl.$parsers.push(maxLengthValidator);
17096    ctrl.$formatters.push(maxLengthValidator);
17097  }
17098}
17099
17100var numberBadFlags = ['badInput'];
17101
17102function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17103  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17104
17105  ctrl.$parsers.push(function(value) {
17106    var empty = ctrl.$isEmpty(value);
17107    if (empty || NUMBER_REGEXP.test(value)) {
17108      ctrl.$setValidity('number', true);
17109      return value === '' ? null : (empty ? value : parseFloat(value));
17110    } else {
17111      ctrl.$setValidity('number', false);
17112      return undefined;
17113    }
17114  });
17115
17116  addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
17117
17118  ctrl.$formatters.push(function(value) {
17119    return ctrl.$isEmpty(value) ? '' : '' + value;
17120  });
17121
17122  if (attr.min) {
17123    var minValidator = function(value) {
17124      var min = parseFloat(attr.min);
17125      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
17126    };
17127
17128    ctrl.$parsers.push(minValidator);
17129    ctrl.$formatters.push(minValidator);
17130  }
17131
17132  if (attr.max) {
17133    var maxValidator = function(value) {
17134      var max = parseFloat(attr.max);
17135      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
17136    };
17137
17138    ctrl.$parsers.push(maxValidator);
17139    ctrl.$formatters.push(maxValidator);
17140  }
17141
17142  ctrl.$formatters.push(function(value) {
17143    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
17144  });
17145}
17146
17147function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17148  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17149
17150  var urlValidator = function(value) {
17151    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
17152  };
17153
17154  ctrl.$formatters.push(urlValidator);
17155  ctrl.$parsers.push(urlValidator);
17156}
17157
17158function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17159  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17160
17161  var emailValidator = function(value) {
17162    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
17163  };
17164
17165  ctrl.$formatters.push(emailValidator);
17166  ctrl.$parsers.push(emailValidator);
17167}
17168
17169function radioInputType(scope, element, attr, ctrl) {
17170  // make the name unique, if not defined
17171  if (isUndefined(attr.name)) {
17172    element.attr('name', nextUid());
17173  }
17174
17175  element.on('click', function() {
17176    if (element[0].checked) {
17177      scope.$apply(function() {
17178        ctrl.$setViewValue(attr.value);
17179      });
17180    }
17181  });
17182
17183  ctrl.$render = function() {
17184    var value = attr.value;
17185    element[0].checked = (value == ctrl.$viewValue);
17186  };
17187
17188  attr.$observe('value', ctrl.$render);
17189}
17190
17191function checkboxInputType(scope, element, attr, ctrl) {
17192  var trueValue = attr.ngTrueValue,
17193      falseValue = attr.ngFalseValue;
17194
17195  if (!isString(trueValue)) trueValue = true;
17196  if (!isString(falseValue)) falseValue = false;
17197
17198  element.on('click', function() {
17199    scope.$apply(function() {
17200      ctrl.$setViewValue(element[0].checked);
17201    });
17202  });
17203
17204  ctrl.$render = function() {
17205    element[0].checked = ctrl.$viewValue;
17206  };
17207
17208  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
17209  ctrl.$isEmpty = function(value) {
17210    return value !== trueValue;
17211  };
17212
17213  ctrl.$formatters.push(function(value) {
17214    return value === trueValue;
17215  });
17216
17217  ctrl.$parsers.push(function(value) {
17218    return value ? trueValue : falseValue;
17219  });
17220}
17221
17222
17223/**
17224 * @ngdoc directive
17225 * @name textarea
17226 * @restrict E
17227 *
17228 * @description
17229 * HTML textarea element control with angular data-binding. The data-binding and validation
17230 * properties of this element are exactly the same as those of the
17231 * {@link ng.directive:input input element}.
17232 *
17233 * @param {string} ngModel Assignable angular expression to data-bind to.
17234 * @param {string=} name Property name of the form under which the control is published.
17235 * @param {string=} required Sets `required` validation error key if the value is not entered.
17236 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17237 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17238 *    `required` when you want to data-bind to the `required` attribute.
17239 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17240 *    minlength.
17241 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17242 *    maxlength.
17243 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17244 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17245 *    patterns defined as scope expressions.
17246 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17247 *    interaction with the input element.
17248 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17249 */
17250
17251
17252/**
17253 * @ngdoc directive
17254 * @name input
17255 * @restrict E
17256 *
17257 * @description
17258 * HTML input element control with angular data-binding. Input control follows HTML5 input types
17259 * and polyfills the HTML5 validation behavior for older browsers.
17260 *
17261 * @param {string} ngModel Assignable angular expression to data-bind to.
17262 * @param {string=} name Property name of the form under which the control is published.
17263 * @param {string=} required Sets `required` validation error key if the value is not entered.
17264 * @param {boolean=} ngRequired Sets `required` attribute if set to true
17265 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17266 *    minlength.
17267 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17268 *    maxlength.
17269 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17270 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17271 *    patterns defined as scope expressions.
17272 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17273 *    interaction with the input element.
17274 *
17275 * @example
17276    <example name="input-directive" module="inputExample">
17277      <file name="index.html">
17278       <script>
17279          angular.module('inputExample', [])
17280            .controller('ExampleController', ['$scope', function($scope) {
17281              $scope.user = {name: 'guest', last: 'visitor'};
17282            }]);
17283       </script>
17284       <div ng-controller="ExampleController">
17285         <form name="myForm">
17286           User name: <input type="text" name="userName" ng-model="user.name" required>
17287           <span class="error" ng-show="myForm.userName.$error.required">
17288             Required!</span><br>
17289           Last name: <input type="text" name="lastName" ng-model="user.last"
17290             ng-minlength="3" ng-maxlength="10">
17291           <span class="error" ng-show="myForm.lastName.$error.minlength">
17292             Too short!</span>
17293           <span class="error" ng-show="myForm.lastName.$error.maxlength">
17294             Too long!</span><br>
17295         </form>
17296         <hr>
17297         <tt>user = {{user}}</tt><br/>
17298         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
17299         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
17300         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
17301         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
17302         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
17303         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
17304         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
17305         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
17306       </div>
17307      </file>
17308      <file name="protractor.js" type="protractor">
17309        var user = element(by.binding('{{user}}
vendor: 2,296 bytes, lines 17309-17363
17309'));
17310        var userNameValid = element(by.binding('myForm.userName.$valid'));
17311        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
17312        var lastNameError = element(by.binding('myForm.lastName.$error'));
17313        var formValid = element(by.binding('myForm.$valid'));
17314        var userNameInput = element(by.model('user.name'));
17315        var userLastInput = element(by.model('user.last'));
17316
17317        it('should initialize to model', function() {
17318          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
17319          expect(userNameValid.getText()).toContain('true');
17320          expect(formValid.getText()).toContain('true');
17321        });
17322
17323        it('should be invalid if empty when required', function() {
17324          userNameInput.clear();
17325          userNameInput.sendKeys('');
17326
17327          expect(user.getText()).toContain('{"last":"visitor"}');
17328          expect(userNameValid.getText()).toContain('false');
17329          expect(formValid.getText()).toContain('false');
17330        });
17331
17332        it('should be valid if empty when min length is set', function() {
17333          userLastInput.clear();
17334          userLastInput.sendKeys('');
17335
17336          expect(user.getText()).toContain('{"name":"guest","last":""}');
17337          expect(lastNameValid.getText()).toContain('true');
17338          expect(formValid.getText()).toContain('true');
17339        });
17340
17341        it('should be invalid if less than required min length', function() {
17342          userLastInput.clear();
17343          userLastInput.sendKeys('xx');
17344
17345          expect(user.getText()).toContain('{"name":"guest"}');
17346          expect(lastNameValid.getText()).toContain('false');
17347          expect(lastNameError.getText()).toContain('minlength');
17348          expect(formValid.getText()).toContain('false');
17349        });
17350
17351        it('should be invalid if longer than max length', function() {
17352          userLastInput.clear();
17353          userLastInput.sendKeys('some ridiculously long name');
17354
17355          expect(user.getText()).toContain('{"name":"guest"}');
17356          expect(lastNameValid.getText()).toContain('false');
17357          expect(lastNameError.getText()).toContain('maxlength');
17358          expect(formValid.getText()).toContain('false');
17359        });
17360      </file>
17361    </example>
17362 */
17363var inputDirective = ['$browser', '$sniffer', 
17363function($browser, $sniffer) {
17364  return {
17365    restrict: 'E',
17366    require: '?ngModel',
17367    link: function(scope, element, attr, ctrl) {
17368      if (ctrl) {
17369        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17370                                                            $browser);
17371      }
17372    }
17373  };
17374}];
17375
17376var VALID_CLASS = 'ng-valid',
17377    INVALID_CLASS = 'ng-invalid',
17378    PRISTINE_CLASS = 'ng-pristine',
17379    DIRTY_CLASS = 'ng-dirty';
17380
17381/**
17382 * @ngdoc type
17383 * @name ngModel.NgModelController
17384 *
17385 * @property {string} $viewValue Actual string value in the view.
17386 * @property {*} $modelValue The value in the model, that the control is bound to.
17387 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17388       the control reads value from the DOM.  Each function is called, in turn, passing the value
17389       through to the next. The last return value is used to populate the model.
17390       Used to sanitize / convert the value as well as validation. For validation,
17391       the parsers should update the validity state using
17392       {@link ngModel.NgModelController#$setValidity $setValidity()},
17393       and return `undefined` for invalid values.
17394
17395 *
17396 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17397       the model value changes. Each function is called, in turn, passing the value through to the
17398       next. Used to format / convert values for display in the control and validation.
17399 * ```js
17400 * function formatter(value) {
17401 *   if (value) {
17402 *     return value.toUpperCase();
17403 *   }
17404 * }
17405 * ngModel.$formatters.push(formatter);
17406 * ```
17407 *
17408 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17409 *     view value has changed. It is called with no arguments, and its return value is ignored.
17410 *     This can be used in place of additional $watches against the model value.
17411 *
17412 * @property {Object} $error An object hash with all errors as keys.
17413 *
17414 * @property {boolean} $pristine True if user has not interacted with the control yet.
17415 * @property {boolean} $dirty True if user has already interacted with the control.
17416 * @property {boolean} $valid True if there is no error.
17417 * @property {boolean} $invalid True if at least one error on the control.
17418 *
17419 * @description
17420 *
17421 * `NgModelController` provides API for the `ng-model` directive. The controller contains
17422 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17423 * purposefully does not contain any logic which deals with DOM rendering or listening to
17424 * DOM events. Such DOM related logic should be provided by other directives which make use of
17425 * `NgModelController` for data-binding.
17426 *
17427 * ## Custom Control Example
17428 * This example shows how to use `NgModelController` with a custom control to achieve
17429 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17430 * collaborate together to achieve the desired result.
17431 *
17432 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17433 * contents be edited in place by the user.  This will not work on older browsers.
17434 *
17435 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
17436 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
17437 * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
17438 * that content using the `$sce` service.
17439 *
17440 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
17441    <file name="style.css">
17442      [contenteditable] {
17443        border: 1px solid black;
17444        background-color: white;
17445        min-height: 20px;
17446      }
17447
17448      .ng-invalid {
17449        border: 1px solid red;
17450      }
17451
17452    </file>
17453    <file name="script.js">
17454      angular.module('customControl', ['ngSanitize']).
17455        directive('contenteditable', ['$sce', function($sce) {
17456          return {
17457            restrict: 'A', // only activate on element attribute
17458            require: '?ngModel', // get a hold of NgModelController
17459            link: function(scope, element, attrs, ngModel) {
17460              if(!ngModel) return; // do nothing if no ng-model
17461
17462              // Specify how UI should be updated
17463              ngModel.$render = function() {
17464                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
17465              };
17466
17467              // Listen for change events to enable binding
17468              element.on('blur keyup change', function() {
17469                scope.$apply(read);
17470              });
17471              read(); // initialize
17472
17473              // Write data to the model
17474              function read() {
17475                var html = element.html();
17476                // When we clear the content editable the browser leaves a <br> behind
17477                // If strip-br attribute is provided then we strip this out
17478                if( attrs.stripBr && html == '<br>' ) {
17479                  html = '';
17480                }
17481                ngModel.$setViewValue(html);
17482              }
17483            }
17484          };
17485        }]);
17486    </file>
17487    <file name="index.html">
17488      <form name="myForm">
17489       <div contenteditable
17490            name="myWidget" ng-model="userContent"
17491            strip-br="true"
17492            required>Change me!</div>
17493        <span ng-show="myForm.myWidget.$error.required">Required!</span>
17494       <hr>
17495       <textarea ng-model="userContent"></textarea>
17496      </form>
17497    </file>
17498    <file name="protractor.js" type="protractor">
17499    it('should data-bind and become invalid', function() {
17500      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17501        // SafariDriver can't handle contenteditable
17502        // and Firefox driver can't clear contenteditables very well
17503        return;
17504      }
17505      var contentEditable = element(by.css('[contenteditable]'));
17506      var content = 'Change me!';
17507
17508      expect(contentEditable.getText()).toEqual(content);
17509
17510      contentEditable.clear();
17511      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17512      expect(contentEditable.getText()).toEqual('');
17513      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17514    });
17515    </file>
17516 * </example>
17517 *
17518 *
17519 */
17520var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17521    function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17522  this.$viewValue = Number.NaN;
17523  this.$modelValue = Number.NaN;
17524  this.$parsers = [];
17525  this.$formatters = [];
17526  this.$viewChangeListeners = [];
17527  this.$pristine = true;
17528  this.$dirty = false;
17529  this.$valid = true;
17530  this.$invalid = false;
17531  this.$name = $attr.name;
17532
17533  var ngModelGet = $parse($attr.ngModel),
17534      ngModelSet = ngModelGet.assign;
17535
17536  if (!ngModelSet) {
17537    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17538        $attr.ngModel, startingTag($element));
17539  }
17540
17541  /**
17542   * @ngdoc method
17543   * @name ngModel.NgModelController#$render
17544   *
17545   * @description
17546   * Called when the view needs to be updated. It is expected that the user of the ng-model
17547   * directive will implement this method.
17548   */
17549  this.$render = noop;
17550
17551  /**
17552   * @ngdoc method
17553   * @name ngModel.NgModelController#$isEmpty
17554   *
17555   * @description
17556   * This is called when we need to determine if the value of the input is empty.
17557   *
17558   * For instance, the required directive does this to work out if the input has data or not.
17559   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17560   *
17561   * You can override this for input directives whose concept of being empty is different to the
17562   * default. The `checkboxInputType` directive does this because in its case a value of `false`
17563   * implies empty.
17564   *
17565   * @param {*} value Reference to check.
17566   * @returns {boolean} True if `value` is empty.
17567   */
17568  this.$isEmpty = function(value) {
17569    return isUndefined(value) || value === '' || value === null || value !== value;
17570  };
17571
17572  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17573      invalidCount = 0, // used to easily determine if we are valid
17574      $error = this.$error = {}; // keep invalid keys here
17575
17576
17577  // Setup initial state of the control
17578  $element.addClass(PRISTINE_CLASS);
17579  toggleValidCss(true);
17580
17581  // convenience method for easy toggling of classes
17582  function toggleValidCss(isValid, validationErrorKey) {
17583    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17584    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17585    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17586  }
17587
17588  /**
17589   * @ngdoc method
17590   * @name ngModel.NgModelController#$setValidity
17591   *
17592   * @description
17593   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17594   * does not notify form if given validator is already marked as invali
17594d).
17595   *
17596   * This method should be called by validators - i.e. the parser or formatter functions.
17597   *
17598   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17599   *        to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
17600   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17601   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17602   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17603   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17604   */
17605  this.$setValidity = function(validationErrorKey, isValid) {
17606    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17607    // jshint -W018
17608    if ($error[validationErrorKey] === !isValid) return;
17609    // jshint +W018
17610
17611    if (isValid) {
17612      if ($error[validationErrorKey]) invalidCount--;
17613      if (!invalidCount) {
17614        toggleValidCss(true);
17615        this.$valid = true;
17616        this.$invalid = false;
17617      }
17618    } else {
17619      toggleValidCss(false);
17620      this.$invalid = true;
17621      this.$valid = false;
17622      invalidCount++;
17623    }
17624
17625    $error[validationErrorKey] = !isValid;
17626    toggleValidCss(isValid, validationErrorKey);
17627
17628    parentForm.$setValidity(validationErrorKey, isValid, this);
17629  };
17630
17631  /**
17632   * @ngdoc method
17633   * @name ngModel.NgModelController#$setPristine
17634   *
17635   * @description
17636   * Sets the control to its pristine state.
17637   *
17638   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17639   * state (ng-pristine class).
17640   */
17641  this.$setPristine = function () {
17642    this.$dirty = false;
17643    this.$pristine = true;
17644    $animate.removeClass($element, DIRTY_CLASS);
17645    $animate.addClass($element, PRISTINE_CLASS);
17646  };
17647
17648  /**
17649   * @ngdoc method
17650   * @name ngModel.NgModelController#$setViewValue
17651   *
17652   * @description
17653   * Update the view value.
17654   *
17655   * This method should be called when the view value changes, typically from within a DOM event handler.
17656   * For example {@link ng.directive:input input} and
17657   * {@link ng.directive:select select} directives call it.
17658   *
17659   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17660   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17661   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17662   *
17663   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17664   *
17665   * Note that calling this function does not trigger a `$digest`.
17666   *
17667   * @param {string} value Value from the view.
17668   */
17669  this.$setViewValue = function(value) {
17670    this.$viewValue = value;
17671
17672    // change to dirty
17673    if (this.$pristine) {
17674      this.$dirty = true;
17675      this.$pristine = false;
17676      $animate.removeClass($element, PRISTINE_CLASS);
17677      $animate.addClass($element, DIRTY_CLASS);
17678      parentForm.$setDirty();
17679    }
17680
17681    forEach(this.$parsers, function(fn) {
17682      value = fn(value);
17683    });
17684
17685    if (this.$modelValue !== value) {
17686      this.$modelValue = value;
17687      ngModelSet($scope, value);
17688      forEach(this.$viewChangeListeners, function(listener) {
17689        try {
17690          listener();
17691        } catch(e) {
17692          $exceptionHandler(e);
17693        }
17694      });
17695    }
17696  };
17697
17698  // model -> value
17699  var ctrl = this;
17700
17701  $scope.$watch(function ngModelWatch() {
17702    var value = ngModelGet($scope);
17703
17704    // if scope model value and ngModel value are out of sync
17705    if (ctrl.$modelValue !== value) {
17706
17707      var formatters = ctrl.$formatters,
17708          idx = formatters.length;
17709
17710      ctrl.$modelValue = value;
17711      while(idx--) {
17712        value = formatters[idx](value);
17713      }
17714
17715      if (ctrl.$viewValue !== value) {
17716        ctrl.$viewValue = value;
17717        ctrl.$render();
17718      }
17719    }
17720
17721    return value;
17722  });
17723}];
17724
17725
17726/**
17727 * @ngdoc directive
17728 * @name ngModel
17729 *
17730 * @element input
17731 *
17732 * @description
17733 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17734 * property on the scope using {@link ngModel.NgModelController NgModelController},
17735 * which is created and exposed by this directive.
17736 *
17737 * `ngModel` is responsible for:
17738 *
17739 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17740 *   require.
17741 * - Providing validation behavior (i.e. required, number, email, url).
17742 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17743 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17744 * - Registering the control with its parent {@link ng.directive:form form}.
17745 *
17746 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17747 * current scope. If the property doesn't already exist on this scope, it will be created
17748 * implicitly and added to the scope.
17749 *
17750 * For best practices on using `ngModel`, see:
17751 *
17752 *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
17753 *
17754 * For basic examples, how to use `ngModel`, see:
17755 *
17756 *  - {@link ng.directive:input input}
17757 *    - {@link input[text] text}
17758 *    - {@link input[checkbox] checkbox}
17759 *    - {@link input[radio] radio}
17760 *    - {@link input[number] number}
17761 *    - {@link input[email] email}
17762 *    - {@link input[url] url}
17763 *  - {@link ng.directive:select select}
17764 *  - {@link ng.directive:textarea textarea}
17765 *
17766 * # CSS classes
17767 * The following CSS classes are added and removed on the associated input/select/textarea element
17768 * depending on the validity of the model.
17769 *
17770 *  - `ng-valid` is set if the model is valid.
17771 *  - `ng-invalid` is set if the model is invalid.
17772 *  - `ng-pristine` is set if the model is pristine.
17773 *  - `ng-dirty` is set if the model is dirty.
17774 *
17775 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
17776 *
17777 * ## Animation Hooks
17778 *
17779 * Animations within models are triggered when any of the associated CSS classes are added and removed
17780 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
17781 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
17782 * The animations that are triggered within ngModel are similar to how they work in ngClass and
17783 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
17784 *
17785 * The following example shows a simple way to utilize CSS transitions to style an input element
17786 * that has been rendered as invalid after it has been validated:
17787 *
17788 * <pre>
17789 * //be sure to include ngAnimate as a module to hook into more
17790 * //advanced animations
17791 * .my-input {
17792 *   transition:0.5s linear all;
17793 *   background: white;
17794 * }
17795 * .my-input.ng-invalid {
17796 *   background: red;
17797 *   color:white;
17798 * }
17799 * </pre>
17800 *
17801 * @example
17802 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
17803     <file name="index.html">
17804       <script>
17805        angular.module('inputExample', [])
17806          .controller('ExampleController', ['$scope', function($scope) {
17807            $scope.val = '1';
17808          }]);
17809       </script>
17810       <style>
17811         .my-input {
17812           -webkit-transition:all linear 0.5s;
17813           transition:all linear 0.5s;
17814           background: transparent;
17815         }
17816         .my-input.ng-invalid {
17817           color:white;
17818           background: red;
17819         }
17820       </style>
17821       Update input to see transitions when valid/invalid.
17822       Integer is a valid value.
17823       <form name="testForm" ng-controller="ExampleController">
17824         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
17825       </form>
17826     </file>
17827 * </example>
17828 */
17829var ngModelDirective = function() {
17830  return {
17831    require: ['ngModel', '^?form'],
17832    controller: NgModelController,
17833    link: function(scope, element, attr, ctrls) {
17834      // notify others, especially parent forms
17835
17836      var modelCtrl = ctrls[0],
17837          formCtrl = ctrls[1] || nullFormCtrl;
17838
17839      formCtrl.$addControl(modelCtrl);
17840
17841      scope.$on('$destroy', function() {
17842        formCtrl.$removeControl(modelCtrl);
17843      });
17844    }
17845  };
17846};
17847
17848
17849/**
17850 * @ngdoc directive
17851 * @name ngChange
17852 *
17853 * @description
17854 * Evaluate the given expression when the user changes the input.
17855 * The expression is evaluated immediately, unlike the JavaScript onchange event
17856 * which only triggers at the end of a change (usually, when the user leaves the
17857 * form element or presses the return key).
17858 * The expression is not evaluated when the value change is coming from the model.
17859 *
17860 * Note, this directive requires `ngModel` to be present.
17861 *
17862 * @element input
17863 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17864 * in input value.
17865 *
17866 * @example
17867 * <example name="ngChange-directive" module="changeExample">
17868 *   <file name="index.html">
17869 *     <script>
17870 *       angular.module('changeExample', [])
17871 *         .controller('ExampleController', ['$scope', function($scope) {
17872 *           $scope.counter = 0;
17873 *           $scope.change = function() {
17874 *             $scope.counter++;
17875 *           };
17876 *         }]);
17877 *     </script>
17878 *     <div ng-controller="ExampleController">
17879 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17880 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17881 *       <label for="ng-change-example2">Confirmed</label><br />
17882 *       <tt>debug = {{confirmed}}</tt><br/>
17883 *       <tt>counter = {{counter}}</tt><br/>
17884 *     </div>
17885 *   </file>
17886 *   <file name="protractor.js" type="protractor">
17887 *     var counter = element(by.binding('counter'));
17888 *     var debug = element(by.binding('confirmed'));
17889 *
17890 *     it('should evaluate the expression if changing from view', function() {
17891 *       expect(counter.getText()).toContain('0');
17892 *
17893 *       element(by.id('ng-change-example1')).click();
17894 *
17895 *       expect(counter.getText()).toContain('1');
17896 *       expect(debug.getText()).toContain('true');
17897 *     });
17898 *
17899 *     it('should not evaluate the expression if changing from model', function() {
17900 *       element(by.id('ng-change-example2')).click();
17901
17902 *       expect(counter.getText()).toContain('0');
17903 *       expect(debug.getText()).toContain('true');
17904 *     });
17905 *   </file>
17906 * </example>
17907 */
17908var ngChangeDirective = valueFn({
17909  require: 'ngModel',
17910  link: function(scope, element, attr, ctrl) {
17911    ctrl.$viewChangeListeners.push(function() {
17912      scope.$eval(attr.ngChange);
17913    });
17914  }
17915});
17916
17917
17918var requiredDirective = function() {
17919  return {
17920    require: '?ngModel',
17921    link: function(scope, elm, attr, ctrl) {
17922      if (!ctrl) return;
17923      attr.required = true; // force truthy in case we are on non input element
17924
17925      var validator = function(value) {
17926        if (attr.required && ctrl.$isEmpty(value)) {
17927          ctrl.$setValidity('required', false);
17928          return;
17929        } else {
17930          ctrl.$setValidity('required', true);
17931          return value;
17932        }
17933      };
17934
17935      ctrl.$formatters.push(validator);
17936      ctrl.$parsers.unshift(validator);
17937
17938      attr.$observe('required', function() {
17939        validator(ctrl.$viewValue);
17940      });
17941    }
17942  };
17943};
17944
17945
17946/**
17947 * @ngdoc directive
17948 * @name ngList
17949 *
17950 * @description
17951 * Text input that converts between a delimited string and an array of strings. The delimiter
17952 * can be a fixed string (by default a comma) or a regular expression.
17953 *
17954 * @element input
17955 * @param {string=} ngList optional delimiter that should be used to split the value. If
17956 *   specified in form `/something/` then the value will be converted into a regular expression.
17957 *
17958 * @example
17959    <example name="ngList-directive" module="listExample">
17960      <file name="index.html">
17961       <script>
17962         angular.module('listExample', [])
17963           .controller('ExampleController', ['$scope', function($scope) {
17964             $scope.names = ['igor', 'misko', 'vojta'];
17965           }]);
17966       </script>
17967       <form name="myForm" ng-controller="ExampleController">
17968         List: <input name="namesInput" ng-model="names" ng-list required>
17969         <span class="error" ng-show="myForm.namesInput.$error.required">
17970           Required!</span>
17971         <br>
17972         <tt>names = {{names}}</tt><br/>
17973         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
17974         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
17975         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
17976         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
17977        </form>
17978      </file>
17979      <file name="protractor.js" type="protractor">
17980        var listInput = element(by.model('names'));
17981        var names = element(by.binding('{{names}}'));
17982        var valid = element(by.binding('myForm.namesInput.$valid'));
17983        var error = element(by.css('span.error'));
17984
17985        it('should initialize to model', function() {
17986          expect(names.getText()).toContain('["igor","misko","vojta"]');
17987          expect(valid.getText()).toContain('true');
17988          expect(error.getCssValue('display')).toBe('none');
17989        });
17990
17991        it('should be invalid if empty', function() {
17992          listInput.clear();
17993          listInput.sendKeys('');
17994
17995          expect(names.getText()).toContain('');
17996          expect(valid.getText()).toContain('false');
17997          expect(error.getCssValue('display')).not.toBe('none');        });
17998      </file>
17999    </example>
18000 */
18001var ngListDirective = function() {
18002  return {
18003    require: 'ngModel',
18004    link: function(scope, element, attr, ctrl) {
18005      var match = /\/(.*)\//.exec(attr.ngList),
18006          separator = match && new RegExp(match[1]) || attr.ngList || ',';
18007
18008      var parse = function(viewValue) {
18009        // If the viewValue is invalid (say required but empty) it will be `undefined`
18010        if (isUndefined(viewValue)) return;
18011
18012        var list = [];
18013
18014        if (viewValue) {
18015          forEach(viewValue.split(separator), function(value) {
18016            if (value) list.push(trim(value));
18017          });
18018        }
18019
18020        return list;
18021      };
18022
18023      ctrl.$parsers.push(parse);
18024      ctrl.$formatters.push(function(value) {
18025        if (isArray(value)) {
18026          return value.join(', ');
18027        }
18028
18029        return undefined;
18030      });
18031
18032      // Override the standard $isEmpty because an empty array means the input is empty.
18033      ctrl.$isEmpty = function(value) {
18034        return !value || !value.length;
18035      };
18036    }
18037  };
18038};
18039
18040
18041var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
18042/**
18043 * @ngdoc directive
18044 * @name ngValue
18045 *
18046 * @description
18047 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
18048 * that when the element is selected, the `ngModel` of that element is set to the
18049 * bound value.
18050 *
18051 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
18052 * shown below.
18053 *
18054 * @element input
18055 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
18056 *   of the `input` element
18057 *
18058 * @example
18059    <example name="ngValue-directive" module="valueExample">
18060      <file name="index.html">
18061       <script>
18062          angular.module('valueExample', [])
18063            .controller('ExampleController', ['$scope', function($scope) {
18064              $scope.names = ['pizza', 'unicorns', 'robots'];
18065              $scope.my = { favorite: 'unicorns' };
18066            }]);
18067       </script>
18068        <form ng-controller="ExampleController">
18069          <h2>Which is your favorite?</h2>
18070            <label ng-repeat="name in names" for="{{name}}">
18071              {{name}}
18072              <input type="radio"
18073                     ng-model="my.favorite"
18074                     ng-value="name"
18075                     id="{{name}}"
18076                     name="favorite">
18077            </label>
18078          <div>You chose {{my.favorite}}</div>
18079        </form>
18080      </file>
18081      <file name="protractor.js" type="protractor">
18082        var favorite = element(by.binding('my.favorite'));
18083
18084        it('should initialize to model', function() {
18085          expect(favorite.getText()).toContain('unicorns');
18086        });
18087        it('should bind the values to the inputs', function() {
18088          element.all(by.model('my.favorite')).get(0).click();
18089          expect(favorite.getText()).toContain('pizza');
18090        });
18091      </file>
18092    </example>
18093 */
18094var ngValueDirective = function() {
18095  return {
18096    priority: 100,
18097    compile: function(tpl, tplAttr) {
18098      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
18099        return function ngValueConstantLink(scope, elm, attr) {
18100          attr.$set('value', scope.$eval(attr.ngValue));
18101        };
18102      } else {
18103        return function ngValueLink(scope, elm, attr) {
18104          scope.$watch(attr.ngValue, function valueWatchAction(value) {
18105            attr.$set('value', value);
18106          });
18107        };
18108      }
18109    }
18110  };
18111};
18112
18113/**
18114 * @ngdoc directive
18115 * @name ngBind
18116 * @restrict AC
18117 *
18118 * @description
18119 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
18120 * with the value of a given expression, and to update the text content when the value of that
18121 * expression changes.
18122 *
18123 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
18124 * `{{ expression }}` which is similar but less verbose.
18125 *
18126 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
18127 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
18128 * element attribute, it makes the bindings invisible to the user while the page is loading.
18129 *
18130 * An alternative solution to this problem would be using the
18131 * {@link ng.directive:ngCloak ngCloak} directive.
18132 *
18133 *
18134 * @element ANY
18135 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
18136 *
18137 * @example
18138 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
18139   <example module="bindExample">
18140     <file name="index.html">
18141       <script>
18142         angular.module('bindExample', [])
18143           .controller('ExampleController', ['$scope', function($scope) {
18144             $scope.name = 'Whirled';
18145           }]);
18146       </script>
18147       <div ng-controller="ExampleController">
18148         Enter name: <input type="text" ng-model="name"><br>
18149         Hello <span ng-bind="name"></span>!
18150       </div>
18151     </file>
18152     <file name="protractor.js" type="protractor">
18153       it('should check ng-bind', function() {
18154         var nameInput = element(by.model('name'));
18155
18156         expect(element(by.binding('name')).getText()).toBe('Whirled');
18157         nameInput.clear();
18158         nameInput.sendKeys('world');
18159         expect(element(by.binding('name')).getText()).toBe('world');
18160       });
18161     </file>
18162   </example>
18163 */
18164var ngBindDirective = ngDirective({
18165  compile: function(templateElement) {
18166    templateElement.addClass('ng-binding');
18167    return function (scope, element, attr) {
18168      element.data('$binding', attr.ngBind);
18169      scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
18170        // We are purposefully using == here rather than === because we want to
18171        // catch when value is "null or undefined"
18172        // jshint -W041
18173        element.text(value == undefined ? '' : value);
18174      });
18175    };
18176  }
18177});
18178
18179
18180/**
18181 * @ngdoc directive
18182 * @name ngBindTemplate
18183 *
18184 * @description
18185 * The `ngBindTemplate` directive specifies that the element
18186 * text content should be replaced with the interpolation of the template
18187 * in the `ngBindTemplate` attribute.
18188 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
18189 * expressions. This directive is needed since some HTML elements
18190 * (such as TITLE and OPTION) cannot contain SPAN elements.
18191 *
18192 * @element ANY
18193 * @param {string} ngBindTemplate template of form
18194 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
18195 *
18196 * @example
18197 * Try it here: enter text in text box and watch the greeting change.
18198   <example module="bindExample">
18199     <file name="index.html">
18200       <script>
18201         angular.module('bindExample', [])
18202           .controller('ExampleController', ['$scope', function ($scope) {
18203             $scope.salutation = 'Hello';
18204             $scope.name = 'World';
18205           }]);
18206       </script>
18207       <div ng-controller="ExampleController">
18208        Salutation: <input type="text" ng-model="salutation"><br>
18209        Name: <input type="text" ng-model="name"><br>
18210        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
18211       </div>
18212     </file>
18213     <file name="protractor.js" type="protractor">
18214       it('should check ng-bind', function() {
18215         var salutationElem = element(by.binding('salutation'));
18216         var salutationInput = element(by.model('salutation'));
18217         var nameInput = element(by.model('name'));
18218
18219         expect(salutationElem.getText()).toBe('Hello World!');
18220
18221         salutationInput.clear();
18222         salutationInput.sendKeys('Greetings');
18223         nameInput.clear();
18224         nameInput.sendKeys('user');
18225
18226         expect(salutationElem.getText()).toBe('Greetings user!');
18227       });
18228     </file>
18229   </example>
18230 */
18231var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
18232  return function(scope, element, attr) {
18233    // TODO: move this to scenario runner
18234    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
18235    element.addClass('ng-binding').data('$binding', interpolateFn);
18236    attr.$observe('ngBindTemplate', function(value) {
18237      element.text(value);
18238    });
18239  };
18240}];
18241
18242
18243/**
18244 * @ngdoc directive
18245 * @name ngBindHtml
18246 *
18247 * @description
18248 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
18249 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
18250 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
18251 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
18252 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
18253 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
18254 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
18255 *
18256 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
18257 * will have an exception (instead of an exploit.)
18258 *
18259 * @element ANY
18260 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18261 *
18262 * @example
18263   Try it here: enter text in text box and watch the greeting change.
18264
18265   <example module="bindHtmlExample" deps="angular-sanitize.js">
18266     <file name="index.html">
18267       <div ng-controller="ExampleController">
18268        <p ng-bind-html="myHTML"></p>
18269       </div>
18270     </file>
18271
18272     <file name="script.js">
18273       angular.module('bindHtmlExample', ['ngSanitize'])
18274         .controller('ExampleController', ['$scope', function($scope) {
18275           $scope.myHTML =
18276              'I am an <code>HTML</code>string with ' +
18277              '<a href="#">links!</a> and other <em>stuff</em>';
18278         }]);
18279     </file>
18280
18281     <file name="protractor.js" type="protractor">
18282       it('should check ng-bind-html', function() {
18283         expect(element(by.binding('myHTML')).getText()).toBe(
18284             'I am an HTMLstring with links! and other stuff');
18285       });
18286     </file>
18287   </example>
18288 */
18289var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
18290  return {
18291    compile: function (tElement) {
18292      tElement.addClass('ng-binding');
18293
18294      return function (scope, element, attr) {
18295        element.data('$binding', attr.ngBindHtml);
18296
18297        var parsed = $parse(attr.ngBindHtml);
18298
18299        function getStringValue() {
18300          return (parsed(scope) || '').toString();
18301        }
18302
18303        scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
18304          element.html($sce.getTrustedHtml(parsed(scope)) || '');
18305        });
18306      };
18307    }
18308  };
18309}];
18310
18311function classDirective(name, selector) {
18312  name = 'ngClass' + name;
18313  return ['$animate', function($animate) {
18314    return {
18315      restrict: 'AC',
18316      link: function(scope, element, attr) {
18317        var oldVal;
18318
18319        scope.$watch(attr[name], ngClassWatchAction, true);
18320
18321        attr.$observe('class', function(value) {
18322          ngClassWatchAction(scope.$eval(attr[name]));
18323        });
18324
18325
18326        if (name !== 'ngClass') {
18327          scope.$watch('$index', function($index, old$index) {
18328            // jshint bitwise: false
18329            var mod = $index & 1;
18330            if (mod !== (old$index & 1)) {
18331              var classes = arrayClasses(scope.$eval(attr[name]));
18332              mod === selector ?
18333                addClasses(classes) :
18334                removeClasses(classes);
18335            }
18336          });
18337        }
18338
18339        function addClasses(classes) {
18340          var newClasses = digestClassCounts(classes, 1);
18341          attr.$addClass(newClasses);
18342        }
18343
18344        function removeClasses(classes) {
18345          var newClasses = digestClassCounts(classes, -1);
18346          attr.$removeClass(newClasses);
18347        }
18348
18349        function digestClassCounts (classes, count) {
18350          var classCounts = element.data('$classCounts') || {};
18351          var classesToUpdate = [];
18352          forEach(classes, function (className) {
18353            if (count > 0 || classCounts[className]) {
18354              classCounts[className] = (classCounts[className] || 0) + count;
18355              if (classCounts[className] === +(count > 0)) {
18356                classesToUpdate.push(className);
18357              }
18358            }
18359          });
18360          element.data('$classCounts', classCounts);
18361          return classesToUpdate.join(' ');
18362        }
18363
18364        function updateClasses (oldClasses, newClasses) {
18365          var toAdd = arrayDifference(newClasses, oldClasses);
18366          var toRemove = arrayDifference(oldClasses, newClasses);
18367          toRemove = digestClassCounts(toRemove, -1);
18368          toAdd = digestClassCounts(toAdd, 1);
18369
18370          if (toAdd.length === 0) {
18371            $animate.removeClass(element, toRemove);
18372          } else if (toRemove.length === 0) {
18373            $animate.addClass(element, toAdd);
18374          } else {
18375            $animate.setClass(element, toAdd, toRemove);
18376          }
18377        }
18378
18379        function ngClassWatchAction(newVal) {
18380          if (selector === true || scope.$index % 2 === selector) {
18381            var newClasses = arrayClasses(newVal || []);
18382            if (!oldVal) {
18383              addClasses(newClasses);
18384            } else if (!equals(newVal,oldVal)) {
18385              var oldClasses = arrayClasses(oldVal);
18386              updateClasses(oldClasses, newClasses);
18387            }
18388          }
18389          oldVal = shallowCopy(newVal);
18390        }
18391      }
18392    };
18393
18394    function arrayDifference(tokens1, tokens2) {
18395      var values = [];
18396
18397      outer:
18398      for(var i = 0; i < tokens1.length; i++) {
18399        var token = tokens1[i];
18400        for(var j = 0; j < tokens2.length; j++) {
18401          if(token == tokens2[j]) continue outer;
18402        }
18403        values.push(token);
18404      }
18405      return values;
18406    }
18407
18408    function arrayClasses (classVal) {
18409      if (isArray(classVal)) {
18410        return classVal;
18411      } else if (isString(classVal)) {
18412        return classVal.split(' ');
18413      } else if (isObject(classVal)) {
18414        var classes = [], i = 0;
18415        forEach(classVal, function(v, k) {
18416          if (v) {
18417            classes = classes.concat(k.split(' '));
18418          }
18419        });
18420        return classes;
18421      }
18422      return classVal;
18423    }
18424  }];
18425}
18426
18427/**
18428 * @ngdoc directive
18429 * @name ngClass
18430 * @restrict AC
18431 *
18432 * @description
18433 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18434 * an expression that represents all classes to be added.
18435 *
18436 * The directive operates in three different ways, depending on which of three types the expression
18437 * evaluates to:
18438 *
18439 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18440 * names.
18441 *
18442 * 2. If the expression evaluates to an array, each element of the array should be a string that is
18443 * one or more space-delimited class names.
18444 *
18445 * 3. If the expression evaluates to an object, then for each key-value pair of the
18446 * object with a truthy value the corresponding key is used as a class name.
18447 *
18448 * The directive won't add duplicate classes if a particular class was already set.
18449 *
18450 * When the expression changes, the previously added classes are removed and only then the
18451 * new classes are added.
18452 *
18453 * @animations
18454 * add - happens just before the class is applied to the element
18455 * remove - happens just before the class is removed from the element
18456 *
18457 * @element ANY
18458 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18459 *   of the evaluation can be a string representing space delimited class
18460 *   names, an array, or a map of class names to boolean values. In the case of a map, the
18461 *   names of the properties whose values are truthy will be added as css classes to the
18462 *   element.
18463 *
18464 * @example Example that demonstrates basic bindings via ngClass directive.
18465   <example>
18466     <file name="index.html">
18467       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18468       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18469       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18470       <input type="checkbox" ng-model="error"> error (apply "red" class)
18471       <hr>
18472       <p ng-class="style">Using String Syntax</p>
18473       <input type="text" ng-model="style" placeholder="Type: bold strike red">
18474       <hr>
18475       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18476       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18477       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18478       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18479     </file>
18480     <file name="style.css">
18481       .strike {
18482         text-decoration: line-through;
18483       }
18484       .bold {
18485           font-weight: bold;
18486       }
18487       .red {
18488           color: red;
18489       }
18490     </file>
18491     <file name="protractor.js" type="protractor">
18492       var ps = element.all(by.css('p'));
18493
18494       it('should let you toggle the class', function() {
18495
18496         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18497         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18498
18499         element(by.model('important')).click();
18500         expect(ps.first().getAttribute('class')).toMatch(/bold/);
18501
18502         element(by.model('error')).click();
18503         expect(ps.first().getAttribute('class')).toMatch(/red/);
18504       });
18505
18506       it('should let you toggle string example', function() {
18507         expect(ps.get(1).getAttribute('class')).toBe('');
18508         element(by.model('style')).clear();
18509         element(by.model('style')).sendKeys('red');
18510         expect(ps.get(1).getAttribute('class')).toBe('red');
18511       });
18512
18513       it('array example should have 3 classes', function() {
18514         expect(ps.last().getAttribute('class')).toBe('');
18515         element(by.model('style1')).sendKeys('bold');
18516         element(by.model('style2')).sendKeys('strike');
18517         element(by.model('style3')).sendKeys('red');
18518         expect(ps.last().getAttribute('class')).toBe('bold strike red');
18519       });
18520     </file>
18521   </example>
18522
18523   ## Animations
18524
18525   The example below demonstrates how to perform animations using ngClass.
18526
18527   <example module="ngAnimate" deps="angular-animate.js" animations="true">
18528     <file name="index.html">
18529      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18530      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18531      <br>
18532      <span class="base-class" ng-class="myVar">Sample Text</span>
18533     </file>
18534     <file name="style.css">
18535       .base-class {
18536         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18537         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18538       }
18539
18540       .base-class.my-class {
18541         color: red;
18542         font-size:3em;
18543       }
18544     </file>
18545     <file name="protractor.js" type="protractor">
18546       it('should check ng-class', function() {
18547         expect(element(by.css('.base-class')).getAttribute('class')).not.
18548           toMatch(/my-class/);
18549
18550         element(by.id('setbtn')).click();
18551
18552         expect(element(by.css('.base-class')).getAttribute('class')).
18553           toMatch(/my-class/);
18554
18555         element(by.id('clearbtn')).click();
18556
18557         expect(element(by.css('.base-class')).getAttribute('class')).not.
18558           toMatch(/my-class/);
18559       });
18560     </file>
18561   </example>
18562
18563
18564   ## ngClass and pre-existing CSS3 Transitions/Animations
18565   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18566   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18567   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18568   to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18569   {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18570 */
18571var ngClassDirective = classDirective('', true);
18572
18573/**
18574 * @ngdoc directive
18575 * @name ngClassOdd
18576 * @restrict AC
18577 *
18578 * @description
18579 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18580 * {@link ng.directive:ngClass ngClass}, except they work in
18581 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18582 *
18583 * This directive can be applied only within the scope of an
18584 * {@link ng.directive:ngRepeat ngRepeat}.
18585 *
18586 * @element ANY
18587 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18588 *   of the evaluation can be a string representing space delimited class names or an array.
18589 *
18590 * @example
18591   <example>
18592     <file name="index.html">
18593        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18594          <li ng-repeat="name in names">
18595           <span ng-class-odd="'odd'" ng-class-even="'even'">
18596             {{name}}
18597           </span>
18598          </li>
18599        </ol>
18600     </file>
18601     <file name="style.css">
18602       .odd {
18603         color: red;
18604       }
18605       .even {
18606         color: blue;
18607       }
18608     </file>
18609     <file name="protractor.js" type="protractor">
18610       it('should check ng-class-odd and ng-class-even', function() {
18611         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18612           toMatch(/odd/);
18613         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18614           toMatch(/even/);
18615       });
18616     </file>
18617   </example>
18618 */
18619var ngClassOddDirective = classDirective('Odd', 0);
18620
18621/**
18622 * @ngdoc directive
18623 * @name ngClassEven
18624 * @restrict AC
18625 *
18626 * @description
18627 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18628 * {@link ng.directive:ngClass ngClass}, except they work in
18629 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18630 *
18631 * This directive can be applied only within the scope of an
18632 * {@link ng.directive:ngRepeat ngRepeat}.
18633 *
18634 * @element ANY
18635 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18636 *   result of the evaluation can be a string representing space delimited class names or an array.
18637 *
18638 * @example
18639   <example>
18640     <file name="index.html">
18641        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18642          <li ng-repeat="name in names">
18643           <span ng-class-odd="'odd'" ng-class-even="'even'">
18644             {{name}} &nbsp; &nbsp; &nbsp;
18645           </span>
18646          </li>
18647        </ol>
18648     </file>
18649     <file name="style.css">
18650       .odd {
18651         color: red;
18652       }
18653       .even {
18654         color: blue;
18655       }
18656     </file>
18657     <file name="protractor.js" type="protractor">
18658       it('should check ng-class-odd and ng-class-even', function() {
18659         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18660           toMatch(/odd/);
18661         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18662           toMatch(/even/);
18663       });
18664     </file>
18665   </example>
18666 */
18667var ngClassEvenDirective = classDirective('Even', 1);
18668
18669/**
18670 * @ngdoc directive
18671 * @name ngCloak
18672 * @restrict AC
18673 *
18674 * @description
18675 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18676 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18677 * directive to avoid the undesirable flicker effect caused by the html template display.
18678 *
18679 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18680 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18681 * of the browser view.
18682 *
18683 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18684 * `angular.min.js`.
18685 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18686 *
18687 * ```css
18688 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18689 *   display: none !important;
18690 * }
18691 * ```
18692 *
18693 * When this css rule is loaded by the browser, all html elements (including their children) that
18694 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18695 * during the compilation of the template it deletes the `ngCloak` element attribute, making
18696 * the compiled element visible.
18697 *
18698 * For the best result, the `angular.js` script must be loaded in the head section of the html
18699 * document; alternatively, the css rule above must be included in the external stylesheet of the
18700 * application.
18701 *
18702 * Legacy browsers, like IE7, do not provide attribute selector support (a
18702dded in CSS 2.1) so they
18703 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18704 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18705 *
18706 * @element ANY
18707 *
18708 * @example
18709   <example>
18710     <file name="index.html">
18711        <div id="template1" ng-cloak>{{ 'hello' }}</div>
18712        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18713     </file>
18714     <file name="protractor.js" type="protractor">
18715       it('should remove the template directive and css class', function() {
18716         expect($('#template1').getAttribute('ng-cloak')).
18717           toBeNull();
18718         expect($('#template2').getAttribute('ng-cloak')).
18719           toBeNull();
18720       });
18721     </file>
18722   </example>
18723 *
18724 */
18725var ngCloakDirective = ngDirective({
18726  compile: function(element, attr) {
18727    attr.$set('ngCloak', undefined);
18728    element.removeClass('ng-cloak');
18729  }
18730});
18731
18732/**
18733 * @ngdoc directive
18734 * @name ngController
18735 *
18736 * @description
18737 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18738 * supports the principles behind the Model-View-Controller design pattern.
18739 *
18740 * MVC components in angular:
18741 *
18742 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
18743 *   are accessed through bindings.
18744 * * View — The template (HTML with data bindings) that is rendered into the View.
18745 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18746 *   logic behind the application to decorate the scope with functions and values
18747 *
18748 * Note that you can also attach controllers to the DOM by declaring it in a route definition
18749 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18750 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18751 * and executed twice.
18752 *
18753 * @element ANY
18754 * @scope
18755 * @param {expression} ngController Name of a globally accessible constructor function or an
18756 *     {@link guide/expression expression} that on the current scope evaluates to a
18757 *     constructor function. The controller instance can be published into a scope property
18758 *     by specifying `as propertyName`.
18759 *
18760 * @example
18761 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18762 * greeting are methods declared on the controller (see source tab). These methods can
18763 * easily be called from the angular markup. Any changes to the data are automatically reflected
18764 * in the View without the need for a manual update.
18765 *
18766 * Two different declaration styles are included below:
18767 *
18768 * * one binds methods and properties directly onto the controller using `this`:
18769 * `ng-controller="SettingsController1 as settings"`
18770 * * one injects `$scope` into the controller:
18771 * `ng-controller="SettingsController2"`
18772 *
18773 * The second option is more common in the Angular community, and is generally used in boilerplates
18774 * and in this guide. However, there are advantages to binding properties directly to the controller
18775 * and avoiding scope.
18776 *
18777 * * Using `controller as` makes it obvious which controller you are accessing in the template when
18778 * multiple controllers apply to an element.
18779 * * If you are writing your controllers as classes you have easier access to the properties and
18780 * methods, which will appear on the scope, from inside the controller code.
18781 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
18782 * inheritance masking primitives.
18783 *
18784 * This example demonstrates the `controller as` syntax.
18785 *
18786 * <example name="ngControllerAs" module="controllerAsExample">
18787 *   <file name="index.html">
18788 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18789 *      Name: <input type="text" ng-model="settings.name"/>
18790 *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18791 *      Contact:
18792 *      <ul>
18793 *        <li ng-repeat="contact in settings.contacts">
18794 *          <select ng-model="contact.type">
18795 *             <option>phone</option>
18796 *             <option>email</option>
18797 *          </select>
18798 *          <input type="text" ng-model="contact.value"/>
18799 *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18800 *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18801 *        </li>
18802 *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18803 *     </ul>
18804 *    </div>
18805 *   </file>
18806 *   <file name="app.js">
18807 *    angular.module('controllerAsExample', [])
18808 *      .controller('SettingsController1', SettingsController1);
18809 *
18810 *    function SettingsController1() {
18811 *      this.name = "John Smith";
18812 *      this.contacts = [
18813 *        {type: 'phone', value: '408 555 1212'},
18814 *        {type: 'email', value: '[email protected]'} ];
18815 *    }
18816 *
18817 *    SettingsController1.prototype.greet = function() {
18818 *      alert(this.name);
18819 *    };
18820 *
18821 *    SettingsController1.prototype.addContact = function() {
18822 *      this.contacts.push({type: 'email', value: '[email protected]'});
18823 *    };
18824 *
18825 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
18826 *     var index = this.contacts.indexOf(contactToRemove);
18827 *      this.contacts.splice(index, 1);
18828 *    };
18829 *
18830 *    SettingsController1.prototype.clearContact = function(contact) {
18831 *      contact.type = 'phone';
18832 *      contact.value = '';
18833 *    };
18834 *   </file>
18835 *   <file name="protractor.js" type="protractor">
18836 *     it('should check controller as', function() {
18837 *       var container = element(by.id('ctrl-as-exmpl'));
18838 *         expect(container.element(by.model('settings.name'))
18839 *           .getAttribute('value')).toBe('John Smith');
18840 *
18841 *       var firstRepeat =
18842 *           container.element(by.repeater('contact in settings.contacts').row(0));
18843 *       var secondRepeat =
18844 *           container.element(by.repeater('contact in settings.contacts').row(1));
18845 *
18846 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18847 *           .toBe('408 555 1212');
18848 *
18849 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
18850 *           .toBe('[email protected]');
18851 *
18852 *       firstRepeat.element(by.linkText('clear')).click();
18853 *
18854 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18855 *           .toBe('');
18856 *
18857 *       container.element(by.linkText('add')).click();
18858 *
18859 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
18860 *           .element(by.model('contact.value'))
18861 *           .getAttribute('value'))
18862 *           .toBe('[email protected]');
18863 *     });
18864 *   </file>
18865 * </example>
18866 *
18867 * This example demonstrates the "attach to `$scope`" style of controller.
18868 *
18869 * <example name="ngController" module="controllerExample">
18870 *  <file name="index.html">
18871 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
18872 *     Name: <input type="text" ng-model="name"/>
18873 *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
18874 *     Contact:
18875 *     <ul>
18876 *       <li ng-repeat="contact in contacts">
18877 *         <select ng-model="contact.type">
18878 *            <option>phone</option>
18879 *            <option>email</option>
18880 *         </select>
18881 *         <input type="text" ng-model="contact.value"/>
18882 *         [ <a href="" ng-click="clearContact(contact)">clear</a>
18883 *         | <a href="" ng-click="removeContact(contact)">X</a> ]
18884 *       </li>
18885 *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18886 *    </ul>
18887 *   </div>
18888 *  </file>
18889 *  <file name="app.js">
18890 *   angular.module('controllerExample', [])
18891 *     .controller('SettingsController2', ['$scope', SettingsController2]);
18892 *
18893 *   function SettingsController2($scope) {
18894 *     $scope.name = "John Smith";
18895 *     $scope.contacts = [
18896 *       {type:'phone', value:'408 555 1212'},
18897 *       {type:'email', value:'[email protected]'} ];
18898 *
18899 *     $scope.greet = function() {
18900 *       alert($scope.name);
18901 *     };
18902 *
18903 *     $scope.addContact = function() {
18904 *       $scope.contacts.push({type:'email', value:'[email protected]'});
18905 *     };
18906 *
18907 *     $scope.removeContact = function(contactToRemove) {
18908 *       var index = $scope.contacts.indexOf(contactToRemove);
18909 *       $scope.contacts.splice(index, 1);
18910 *     };
18911 *
18912 *     $scope.clearContact = function(contact) {
18913 *       contact.type = 'phone';
18914 *       contact.value = '';
18915 *     };
18916 *   }
18917 *  </file>
18918 *  <file name="protractor.js" type="protractor">
18919 *    it('should check controller', function() {
18920 *      var container = element(by.id('ctrl-exmpl'));
18921 *
18922 *      expect(container.element(by.model('name'))
18923 *          .getAttribute('value')).toBe('John Smith');
18924 *
18925 *      var firstRepeat =
18926 *          container.element(by.repeater('contact in contacts').row(0));
18927 *      var secondRepeat =
18928 *          container.element(by.repeater('contact in contacts').row(1));
18929 *
18930 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18931 *          .toBe('408 555 1212');
18932 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
18933 *          .toBe('[email protected]');
18934 *
18935 *      firstRepeat.element(by.linkText('clear')).click();
18936 *
18937 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
18938 *          .toBe('');
18939 *
18940 *      container.element(by.linkText('add')).click();
18941 *
18942 *      expect(container.element(by.repeater('contact in contacts').row(2))
18943 *          .element(by.model('contact.value'))
18944 *          .getAttribute('value'))
18945 *          .toBe('[email protected]');
18946 *    });
18947 *  </file>
18948 *</example>
18949
18950 */
18951var ngControllerDirective = [function() {
18952  return {
18953    scope: true,
18954    controller: '@',
18955    priority: 500
18956  };
18957}];
18958
18959/**
18960 * @ngdoc directive
18961 * @name ngCsp
18962 *
18963 * @element html
18964 * @description
18965 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
18966 *
18967 * This is necessary when developing things like Google Chrome Extensions.
18968 *
18969 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
18970 * For Angular to be CSP compatible there are only two things that we need to do differently:
18971 *
18972 * - don't use `Function` constructor to generate optimized value getters
18973 * - don't inject custom stylesheet into the document
18974 *
18975 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
18976 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
18977 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
18978 * be raised.
18979 *
18980 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
18981 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
18982 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
18983 *
18984 * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
18985 * autodetection however triggers a CSP error to be logged in the console:
18986 *
18987 * ```
18988 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
18989 * script in the following Content Security Policy directive: "default-src 'self'". Note that
18990 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
18991 * ```
18992 *
18993 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
18994 * directive on the root element of the application or on the `angular.js` script tag, whichever
18995 * appears first in the html document.
18996 *
18997 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
18998 *
18999 * @example
19000 * This example shows how to apply the `ngCsp` directive to the `html` tag.
19001   ```html
19002     <!doctype html>
19003     <html ng-app ng-csp>
19004     ...
19005     ...
19006     </html>
19007   ```
19008 */
19009
19010// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
19011// bootstrap the system (before $parse is instantiated), for this reason we just have
19012// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
19013
19014/**
19015 * @ngdoc directive
19016 * @name ngClick
19017 *
19018 * @description
19019 * The ngClick directive allows you to specify custom behavior when
19020 * an element is clicked.
19021 *
19022 * @element ANY
19023 * @priority 0
19024 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
19025 * click. ({@link guide/expression#-event- Event object is available as `$event`})
19026 *
19027 * @example
19028   <example>
19029     <file name="index.html">
19030      <button ng-click="count = count + 1" ng-init="count=0">
19031        Increment
19032      </button>
19033      count: {{count}}
19034     </file>
19035     <file name="protractor.js" type="protractor">
19036       it('should check ng-click', function() {
19037         expect(element(by.binding('count')).getText()).toMatch('0');
19038         element(by.css('button')).click();
19039         expect(element(by.binding('count')).getText()).toMatch('1');
19040       });
19041     </file>
19042   </example>
19043 */
19044/*
19045 * A directive that allows creation of custom onclick handlers that are defined as angular
19046 * expressions and are compiled and executed within the current scope.
19047 *
19048 * Events that are handled via these handler are always configured not to propagate further.
19049 */
19050var ngEventDirectives = {};
19051forEach(
19052  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
19053  function(name) {
19054    var directiveName = directiveNormalize('ng-' + name);
19055    ngEventDirectives[directiveName] = ['$parse', function($parse) {
19056      return {
19057        compile: function($element, attr) {
19058          var fn = $parse(attr[directiveName]);
19059          return function ngEventHandler(scope, element) {
19060            element.on(lowercase(name), function(event) {
19061              scope.$apply(function() {
19062                fn(scope, {$event:event});
19063              });
19064            });
19065          };
19066        }
19067      };
19068    }];
19069  }
19070);
19071
19072/**
19073 * @ngdoc directive
19074 * @name ngDblclick
19075 *
19076 * @description
19077 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
19078 *
19079 * @element ANY
19080 * @priority 0
19081 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
19082 * a dblclick. (The Event object is available as `$event`)
19083 *
19084 * @example
19085   <example>
19086     <file name="index.html">
19087      <button ng-dblclick="count = count + 1" ng-init="count=0">
19088        Increment (on double click)
19089      </button>
19090      count: {{count}}
19091     </file>
19092   </example>
19093 */
19094
19095
19096/**
19097 * @ngdoc directive
19098 * @name ngMousedown
19099 *
19100 * @description
19101 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
19102 *
19103 * @element ANY
19104 * @priority 0
19105 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
19106 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
19107 *
19108 * @example
19109   <example>
19110     <file name="index.html">
19111      <button ng-mousedown="count = count + 1" ng-init="count=0">
19112        Increment (on mouse down)
19113      </button>
19114      count: {{count}}
19115     </file>
19116   </example>
19117 */
19118
19119
19120/**
19121 * @ngdoc directive
19122 * @name ngMouseup
19123 *
19124 * @description
19125 * Specify custom behavior on mouseup event.
19126 *
19127 * @element ANY
19128 * @priority 0
19129 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
19130 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
19131 *
19132 * @example
19133   <example>
19134     <file name="index.html">
19135      <button ng-mouseup="count = count + 1" ng-init="count=0">
19136        Increment (on mouse up)
19137      </button>
19138      count: {{count}}
19139     </file>
19140   </example>
19141 */
19142
19143/**
19144 * @ngdoc directive
19145 * @name ngMouseover
19146 *
19147 * @description
19148 * Specify custom behavior on mouseover event.
19149 *
19150 * @element ANY
19151 * @priority 0
19152 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
19153 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
19154 *
19155 * @example
19156   <example>
19157     <file name="index.html">
19158      <button ng-mouseover="count = count + 1" ng-init="count=0">
19159        Increment (when mouse is over)
19160      </button>
19161      count: {{count}}
19162     </file>
19163   </example>
19164 */
19165
19166
19167/**
19168 * @ngdoc directive
19169 * @name ngMouseenter
19170 *
19171 * @description
19172 * Specify custom behavior on mouseenter event.
19173 *
19174 * @element ANY
19175 * @priority 0
19176 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
19177 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
19178 *
19179 * @example
19180   <example>
19181     <file name="index.html">
19182      <button ng-mouseenter="count = count + 1" ng-init="count=0">
19183        Increment (when mouse enters)
19184      </button>
19185      count: {{count}}
19186     </file>
19187   </example>
19188 */
19189
19190
19191/**
19192 * @ngdoc directive
19193 * @name ngMouseleave
19194 *
19195 * @description
19196 * Specify custom behavior on mouseleave event.
19197 *
19198 * @element ANY
19199 * @priority 0
19200 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
19201 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
19202 *
19203 * @example
19204   <example>
19205     <file name="index.html">
19206      <button ng-mouseleave="count = count + 1" ng-init="count=0">
19207        Increment (when mouse leaves)
19208      </button>
19209      count: {{count}}
19210     </file>
19211   </example>
19212 */
19213
19214
19215/**
19216 * @ngdoc directive
19217 * @name ngMousemove
19218 *
19219 * @description
19220 * Specify custom behavior on mousemove event.
19221 *
19222 * @element ANY
19223 * @priority 0
19224 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
19225 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
19226 *
19227 * @example
19228   <example>
19229     <file name="index.html">
19230      <button ng-mousemove="count = count + 1" ng-init="count=0">
19231        Increment (when mouse moves)
19232      </button>
19233      count: {{count}}
19234     </file>
19235   </example>
19236 */
19237
19238
19239/**
19240 * @ngdoc directive
19241 * @name ngKeydown
19242 *
19243 * @description
19244 * Specify custom behavior on keydown event.
19245 *
19246 * @element ANY
19247 * @priority 0
19248 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
19249 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19250 *
19251 * @example
19252   <example>
19253     <file name="index.html">
19254      <input ng-keydown="count = count + 1" ng-init="count=0">
19255      key down count: {{count}}
19256     </file>
19257   </example>
19258 */
19259
19260
19261/**
19262 * @ngdoc directive
19263 * @name ngKeyup
19264 *
19265 * @description
19266 * Specify custom behavior on keyup event.
19267 *
19268 * @element ANY
19269 * @priority 0
19270 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
19271 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19272 *
19273 * @example
19274   <example>
19275     <file name="index.html">
19276       <p>Typing in the input box below updates the key count</p>
19277       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
19278
19279       <p>Typing in the input box below updates the keycode</p>
19280       <input ng-keyup="event=$event">
19281       <p>event keyCode: {{ event.keyCode }}</p>
19282       <p>event altKey: {{ event.altKey }}</p>
19283     </file>
19284   </example>
19285 */
19286
19287
19288/**
19289 * @ngdoc directive
19290 * @name ngKeypress
19291 *
19292 * @description
19293 * Specify custom behavior on keypress event.
19294 *
19295 * @element ANY
19296 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
19297 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
19298 * and can be interrogated for keyCode, altKey, etc.)
19299 *
19300 * @example
19301   <example>
19302     <file name="index.html">
19303      <input ng-keypress="count = count + 1" ng-init="count=0">
19304      key press count: {{count}}
19305     </file>
19306   </example>
19307 */
19308
19309
19310/**
19311 * @ngdoc directive
19312 * @name ngSubmit
19313 *
19314 * @description
19315 * Enables binding angular expressions to onsubmit events.
19316 *
19317 * Additionally it prevents the default action (which for form means 
19317sending the request to the
19318 * server and reloading the current page), but only if the form does not contain `action`,
19319 * `data-action`, or `x-action` attributes.
19320 *
19321 * <div class="alert alert-warning">
19322 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
19323 * `ngSubmit` handlers together. See the
19324 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
19325 * for a detailed discussion of when `ngSubmit` may be triggered.
19326 * </div>
19327 *
19328 * @element form
19329 * @priority 0
19330 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
19331 * ({@link guide/expression#-event- Event object is available as `$event`})
19332 *
19333 * @example
19334   <example module="submitExample">
19335     <file name="index.html">
19336      <script>
19337        angular.module('submitExample', [])
19338          .controller('ExampleController', ['$scope', function($scope) {
19339            $scope.list = [];
19340            $scope.text = 'hello';
19341            $scope.submit = function() {
19342              if ($scope.text) {
19343                $scope.list.push(this.text);
19344                $scope.text = '';
19345              }
19346            };
19347          }]);
19348      </script>
19349      <form ng-submit="submit()" ng-controller="ExampleController">
19350        Enter text and hit enter:
19351        <input type="text" ng-model="text" name="text" />
19352        <input type="submit" id="submit" value="Submit" />
19353        <pre>list={{list}}</pre>
19354      </form>
19355     </file>
19356     <file name="protractor.js" type="protractor">
19357       it('should check ng-submit', function() {
19358         expect(element(by.binding('list')).getText()).toBe('list=[]');
19359         element(by.css('#submit')).click();
19360         expect(element(by.binding('list')).getText()).toContain('hello');
19361         expect(element(by.model('text')).getAttribute('value')).toBe('');
19362       });
19363       it('should ignore empty strings', function() {
19364         expect(element(by.binding('list')).getText()).toBe('list=[]');
19365         element(by.css('#submit')).click();
19366         element(by.css('#submit')).click();
19367         expect(element(by.binding('list')).getText()).toContain('hello');
19368        });
19369     </file>
19370   </example>
19371 */
19372
19373/**
19374 * @ngdoc directive
19375 * @name ngFocus
19376 *
19377 * @description
19378 * Specify custom behavior on focus event.
19379 *
19380 * @element window, input, select, textarea, a
19381 * @priority 0
19382 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
19383 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
19384 *
19385 * @example
19386 * See {@link ng.directive:ngClick ngClick}
19387 */
19388
19389/**
19390 * @ngdoc directive
19391 * @name ngBlur
19392 *
19393 * @description
19394 * Specify custom behavior on blur event.
19395 *
19396 * @element window, input, select, textarea, a
19397 * @priority 0
19398 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
19399 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
19400 *
19401 * @example
19402 * See {@link ng.directive:ngClick ngClick}
19403 */
19404
19405/**
19406 * @ngdoc directive
19407 * @name ngCopy
19408 *
19409 * @description
19410 * Specify custom behavior on copy event.
19411 *
19412 * @element window, input, select, textarea, a
19413 * @priority 0
19414 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
19415 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
19416 *
19417 * @example
19418   <example>
19419     <file name="index.html">
19420      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
19421      copied: {{copied}}
19422     </file>
19423   </example>
19424 */
19425
19426/**
19427 * @ngdoc directive
19428 * @name ngCut
19429 *
19430 * @description
19431 * Specify custom behavior on cut event.
19432 *
19433 * @element window, input, select, textarea, a
19434 * @priority 0
19435 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
19436 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
19437 *
19438 * @example
19439   <example>
19440     <file name="index.html">
19441      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
19442      cut: {{cut}}
19443     </file>
19444   </example>
19445 */
19446
19447/**
19448 * @ngdoc directive
19449 * @name ngPaste
19450 *
19451 * @description
19452 * Specify custom behavior on paste event.
19453 *
19454 * @element window, input, select, textarea, a
19455 * @priority 0
19456 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19457 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19458 *
19459 * @example
19460   <example>
19461     <file name="index.html">
19462      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19463      pasted: {{paste}}
19464     </file>
19465   </example>
19466 */
19467
19468/**
19469 * @ngdoc directive
19470 * @name ngIf
19471 * @restrict A
19472 *
19473 * @description
19474 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19475 * {expression}. If the expression assigned to `ngIf` evaluates to a false
19476 * value then the element is removed from the DOM, otherwise a clone of the
19477 * element is reinserted into the DOM.
19478 *
19479 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19480 * element in the DOM rather than changing its visibility via the `display` css property.  A common
19481 * case when this difference is significant is when using css selectors that rely on an element's
19482 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
19482s.
19483 *
19484 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19485 * is created when the element is restored.  The scope created within `ngIf` inherits from
19486 * its parent scope using
19487 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
19488 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19489 * a javascript primitive defined in the parent scope. In this case any modifications made to the
19490 * variable within the child scope will override (hide) the value in the parent scope.
19491 *
19492 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19493 * is if an element's class attribute is directly modified after it's compiled, using something like
19494 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19495 * the added class will be lost because the original compiled state is used to regenerate the element.
19496 *
19497 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19498 * and `leave` effects.
19499 *
19500 * @animations
19501 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
19502 * leave - happens just before the ngIf contents are removed from the DOM
19503 *
19504 * @element ANY
19505 * @scope
19506 * @priority 600
19507 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19508 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19509 *     element is added to the DOM tree.
19510 *
19511 * @example
19512  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19513    <file name="index.html">
19514      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19515      Show when checked:
19516      <span ng-if="checked" class="animate-if">
19517        I'm removed when the checkbox is unchecked.
19518      </span>
19519    </file>
19520    <file name="animations.css">
19521      .animate-if {
19522        background:white;
19523        border:1px solid black;
19524        padding:10px;
19525      }
19526
19527      .animate-if.ng-enter, .animate-if.ng-leave {
19528        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19529        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19530      }
19531
19532      .animate-if.ng-enter,
19533      .animate-if.ng-leave.ng-leave-active {
19534        opacity:0;
19535      }
19536
19537      .animate-if.ng-leave,
19538      .animate-if.ng-enter.ng-enter-active {
19539        opacity:1;
19540      }
19541    </file>
19542  </example>
19543 */
19544var ngIfDirective = ['$animate', function($animate) {
19545  return {
19546    transclude: 'element',
19547    priority: 600,
19548    terminal: true,
19549    restrict: 'A',
19550    $$tlb: true,
19551    link: function ($scope, $element, $attr, ctrl, $transclude) {
19552        var block, childScope, previousElements;
19553        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19554
19555          if (toBoolean(value)) {
19556            if (!childScope) {
19557              childScope = $scope.$new();
19558              $transclude(childScope, function (clone) {
19559                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19560                // Note: We only need the first/last node of the cloned nodes.
19561                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19562                // by a directive with templateUrl when its template arrives.
19563                block = {
19564                  clone: clone
19565                };
19566                $animate.enter(clone, $element.parent(), $element);
19567              });
19568            }
19569          } else {
19570            if(previousElements) {
19571              previousElements.remove();
19572              previousElements = null;
19573            }
19574            if(childScope) {
19575              childScope.$destroy();
19576              childScope = null;
19577            }
19578            if(block) {
19579              previousElements = getBlockElements(block.clone);
19580              $animate.leave(previousElements, function() {
19581                previousElements = null;
19582              });
19583              block = null;
19584            }
19585          }
19586        });
19587    }
19588  };
19589}];
19590
19591/**
19592 * @ngdoc directive
19593 * @name ngInclude
19594 * @restrict ECA
19595 *
19596 * @description
19597 * Fetches, compiles and includes an external HTML fragment.
19598 *
19599 * By default, the template URL is restricted to the same domain and protocol as the
19600 * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19601 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19602 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19603 * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19604 * ng.$sce Strict Contextual Escaping}.
19605 *
19606 * In addition, the browser's
19607 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19608 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19609 * policy may further restrict whether the template is successfully loaded.
19610 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19611 * access on some browsers.
19612 *
19613 * @animations
19614 * enter - animation is used to bring new content into the browser.
19615 * leave - animation is used to animate existing content away.
19616 *
19617 * The enter and leave animation occur concurrently.
19618 *
19619 * @scope
19620 * @priority 400
19621 *
19622 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19623 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19624 * @param {string=} onload Expression to evaluate when a new partial is loaded.
19625 *
19626 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19627 *                  $anchorScroll} to scroll the viewport after the content is loaded.
19628 *
19629 *                  - If the attribute is not set, disable scrolling.
19630 *                  - If the attribute is set without value, enable scrolling.
19631 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19632 *
19633 * @example
19634  <example module="includeExample" deps="angular-animate.js" animations="true">
19635    <file name="index.html">
19636     <div ng-controller="ExampleController">
19637       <select ng-model="template" ng-options="t.name for t in templates">
19638        <option value="">(blank)</option>
19639       </select>
19640       url of the template: <tt>{{template.url}}</tt>
19641       <hr/>
19642       <div class="slide-animate-container">
19643         <div class="slide-animate" ng-include="template.url"></div>
19644       </div>
19645     </div>
19646    </file>
19647    <file name="script.js">
19648      angular.module('includeExample', ['ngAnimate'])
19649        .controller('ExampleController', ['$scope', function($scope) {
19650          $scope.templates =
19651            [ { name: 'template1.html', url: 'template1.html'},
19652              { name: 'template2.html', url: 'template2.html'} ];
19653          $scope.template = $scope.templates[0];
19654        }]);
19655     </file>
19656    <file name="template1.html">
19657      Content of template1.html
19658    </file>
19659    <file name="template2.html">
19660      Content of template2.html
19661    </file>
19662    <file name="animations.css">
19663      .slide-animate-container {
19664        position:relative;
19665        background:white;
19666        border:1px solid black;
19667        height:40px;
19668        overflow:hidden;
19669      }
19670
19671      .slide-animate {
19672        padding:10px;
19673      }
19674
19675      .slide-animate.ng-enter, .slide-animate.ng-leave {
19676        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19677        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19678
19679        position:absolute;
19680        top:0;
19681        left:0;
19682        right:0;
19683        bottom:0;
19684        display:block;
19685        padding:10px;
19686      }
19687
19688      .slide-animate.ng-enter {
19689        top:-50px;
19690      }
19691      .slide-animate.ng-enter.ng-enter-active {
19692        top:0;
19693      }
19694
19695      .slide-animate.ng-leave {
19696        top:0;
19697      }
19698      .slide-animate.ng-leave.ng-leave-active {
19699        top:50px;
19700      }
19701    </file>
19702    <file name="protractor.js" type="protractor">
19703      var templateSelect = element(by.model('template'));
19704      var includeElem = element(by.css('[ng-include]'));
19705
19706      it('should load template1.html', function() {
19707        expect(includeElem.getText()).toMatch(/Content of template1.html/);
19708      });
19709
19710      it('should load template2.html', function() {
19711        if (browser.params.browser == 'firefox') {
19712          // Firefox can't handle using selects
19713          // See https://github.com/angular/protractor/issues/480
19714          return;
19715        }
19716        templateSelect.click();
19717        templateSelect.all(by.css('option')).get(2).click();
19718        expect(includeElem.getText()).toMatch(/Content of template2.html/);
19719      });
19720
19721      it('should change to blank', function() {
19722        if (browser.params.browser == 'firefox') {
19723          // Firefox can't handle using selects
19724          return;
19725        }
19726        templateSelect.click();
19727        templateSelect.all(by.css('option')).get(0).click();
19728        expect(includeElem.isPresent()).toBe(false);
19729      });
19730    </file>
19731  </example>
19732 */
19733
19734
19735/**
19736 * @ngdoc event
19737 * @name ngInclude#$includeContentRequested
19738 * @eventType emit on the scope ngInclude was declared in
19739 * @description
19740 * Emitted every time the ngInclude content is requested.
19741 */
19742
19743
19744/**
19745 * @ngdoc event
19746 * @name ngInclude#$includeContentLoaded
19747 * @eventType emit on the current ngInclude scope
19748 * @description
19749 * Emitted every time the ngInclude content is reloaded.
19750 */
19751var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
19752                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
19753  return {
19754    restrict: 'ECA',
19755    priority: 400,
19756    terminal: true,
19757    transclude: 'element',
19758    controller: angular.noop,
19759    compile: function(element, attr) {
19760      var srcExp = attr.ngInclude || attr.src,
19761          onloadExp = attr.onload || '',
19762          autoScrollExp = attr.autoscroll;
19763
19764      return function(scope, $element, $attr, ctrl, $transclude) {
19765        var changeCounter = 0,
19766            currentScope,
19767            previousElement,
19768            currentElement;
19769
19770        var cleanupLastIncludeContent = function() {
19771          if(previousElement) {
19772            previousElement.remove();
19773            previousElement = null;
19774          }
19775          if(currentScope) {
19776            currentScope.$destroy();
19777            currentScope = null;
19778          }
19779          if(currentElement) {
19780            $animate.leave(currentElement, function() {
19781              previousElement = null;
19782            });
19783            previousElement = currentElement;
19784            currentElement = null;
19785          }
19786        };
19787
19788        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
19789          var afterAnimation = function() {
19790            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
19791              $anchorScroll();
19792            }
19793          };
19794          var thisChangeId = ++changeCounter;
19795
19796          if (src) {
19797            $http.get(src, {cache: $templateCache}).success(function(response) {
19798              if (thisChangeId !== changeCounter) return;
19799              var newScope = scope.$new();
19800              ctrl.template = response;
19801
19802              // Note: This will also link all children of ng-include that were contained in the original
19803              // html. If that content contains controllers, ... they could pollute/change the scope.
19804              // However, using ng-include on an element with additional content does not make sense...
19805              // Note: We can't remove them in the cloneAttchFn of $transclude as that
19806              // function is called before linking the content, which would apply child
19807              // directives to non existing elements.
19808              var clone = $transclude(newScope, function(clone) {
19809                cleanupLastIncludeContent();
19810                $animate.enter(clone, null, $element, afterAnimation);
19811              });
19812
19813              currentScope = newScope;
19814              currentElement = clone;
19815
19816              currentScope.$emit('$includeContentLoaded');
19817              scope.$eval(onloadExp);
19818            }).error(function() {
19819              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
19820            });
19821            scope.$emit('$includeContentRequested');
19822          } else {
19823            cleanupLastIncludeContent();
19824            ctrl.template = null;
19825          }
19826        });
19827      };
19828    }
19829  };
19830}];
19831
19832// This directive is called during the $transclude call of the first `ngInclude` directive.
19833// It will replace and compile the content of the element with the loaded template.
19834// We need this directive so that the element content is already filled when
19835// the link function of another directive on the same element as ngInclude
19836// is called.
19837var ngIncludeFillContentDirective = ['$compile',
19838  function($compile) {
19839    return {
19840      restrict: 'ECA',
19841      priority: -400,
19842      require: 'ngInclude',
19843      link: function(scope, $element, $attr, ctrl) {
19844        $element.html(ctrl.template);
19845        $compile($element.contents())(scope);
19846      }
19847    };
19848  }];
19849
19850/**
19851 * @ngdoc directive
19852 * @name ngInit
19853 * @restrict AC
19854 *
19855 * @description
19856 * The `ngInit` directive allows you to evaluate an expression in the
19857 * current scope.
19858 *
19859 * <div class="alert alert-error">
19860 * The only appropriate use of `ngInit` is for aliasing special properties of
19861 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
19862 * should use {@link guide/controller controllers} rather than `ngInit`
19863 * to initialize values on a scope.
19864 * </div>
19865 * <div class="alert alert-warning">
19866 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
19867 * sure you have parenthesis for correct precedence:
19868 * <pre class="prettyprint">
19869 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
19870 * </pre>
19871 * </div>
19872 *
19873 * @priority 450
19874 *
19875 * @element ANY
19876 * @param {expression} ngInit {@link guide/expression Expression} to eval.
19877 *
19878 * @example
19879   <example module="initExample">
19880     <file name="index.html">
19881   <script>
19882     angular.module('initExample', [])
19883       .controller('ExampleController', ['$scope', function($scope) {
19884         $scope.list = [['a', 'b'], ['c', 'd']];
19885       }]);
19886   </script>
19887   <div ng-controller="ExampleController">
19888     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
19889       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
19890          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
19891       </div>
19892     </div>
19893   </div>
19894     </file>
19895     <file name="protractor.js" type="protractor">
19896       it('should alias index positions', function() {
19897         var elements = element.all(by.css('.example-init'));
19898         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
19899         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
19900         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
19901         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
19902       });
19903     </file>
19904   </example>
19905 */
19906var ngInitDirective = ngDirective({
19907  priority: 450,
19908  compile: function() {
19909    return {
19910      pre: function(scope, element, attrs) {
19911        scope.$eval(attrs.ngInit);
19912      }
19913    };
19914  }
19915});
19916
19917/**
19918 * @ngdoc directive
19919 * @name ngNonBindable
19920 * @restrict AC
19921 * @priority 1000
19922 *
19923 * @description
19924 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
19925 * DOM element. This is useful if the element contains what appears to be Angular directives and
19926 * bindings but which should be ignored by Angular. This could be the case if you have a site that
19927 * displays snippets of code, for instance.
19928 *
19929 * @element ANY
19930 *
19931 * @example
19932 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
19933 * but the one wrapped in `ngNonBindable` is left alone.
19934 *
19935 * @example
19936    <example>
19937      <file name="index.html">
19938        <div>Normal: {{1 + 2}}</div>
19939        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
19940      </file>
19941      <file name="protractor.js" type="protractor">
19942       it('should check ng-non-bindable', function() {
19943         expect(element(by.binding('1 + 2')).getText()).toContain('3');
19944         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
19945       });
19946      </file>
19947    </example>
19948 */
19949var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
19950
19951/**
19952 * @ngdoc directive
19953 * @name ngPluralize
19954 * @restrict EA
19955 *
19956 * @description
19957 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
19958 * These rules are bundled with angular.js, but can be overridden
19959 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
19960 * by specifying the mappings between
19961 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19962 * and the strings to be displayed.
19963 *
19964 * # Plural categories and explicit number rules
19965 * There are two
19966 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19967 * in Angular's default en-US locale: "one" and "other".
19968 *
19969 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
19970 * any number that is not 1), an explicit number rule can only match one number. For example, the
19971 * explicit number rule for "3" matches the number 3. There are examples of plural categories
19972 * and explicit number rules throughout the rest of this documentation.
19973 *
19974 * # Configuring ngPluralize
19975 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
19976 * You can also provide an optional attribute, `offset`.
19977 *
19978 * The value of the `count` attribute can be either a string or an {@link guide/expression
19979 * Angular expression}; these are evaluated on the current scope for its bound value.
19980 *
19981 * The `when` attribute specifies the mappings between plural categories and the actual
19982 * string to be displayed. The value of the attribute should be a JSON object.
19983 *
19984 * The following example shows how to configure ngPluralize:
19985 *
19986 * ```html
19987 * <ng-pluralize count="personCount"
19988                 when="{'0': 'Nobody is viewing.',
19989 *                      'one': '1 person is viewing.',
19990 *                      'other': '{} people are viewing.'}">
19991 * </ng-pluralize>
19992 *```
19993 *
19994 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
19995 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
19996 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
19997 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
19998 * show "a dozen people are viewing".
19999 *
20000 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
20001 * into pluralized strings. In the previous example, Angular will replace `{}` with
20002 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
20003 * for <span ng-non-bindable>{{numberExpression}}</span>.
20004 *
20005 * # Configuring ngPluralize with offset
20006 * The `offset` attribute allows further customization of pluralized text, which can result in
20007 * a better user experience. For example, instead of the message "4 people are viewing this document",
20008 * you might display "John, Kate and 2 others are viewing this document".
20009 * The offset attribute allows you to offset a number by any desired value.
20010 * Let's take a look at an example:
20011 *
20012 * ```html
20013 * <ng-pluralize count="personCount" offset=2
20014 *               when="{'0': 'Nobody is viewing.',
20015 *                      '1': '{{person1}} is viewing.',
20016 *                      '2': '{{person1}} and {{person2}} are viewing.',
20017 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
20018 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20019 * </ng-pluralize>
20020 * ```
20021 *
20022 * Notice that we are still using two plural categories(one, other), but we added
20023 * three explicit number rules 0, 1 and 2.
20024 * When one person, perhaps John, views the document, "John is viewing" will be shown.
20025 * When three people view the document, no explicit number rule is found, so
20026 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
20027 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
20028 * is shown.
20029 *
20030 * Note that when you specify offsets, you must provide explicit number rules for
20031 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
20032 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
20033 * plural categories "one" and "other".
20034 *
20035 * @param {string|expression} count The variable to be bound to.
20036 * @param {string} when The mapping between plural category to its corresponding strings.
20037 * @param {number=} offset Offset to deduct from the total number.
20038 *
20039 * @example
20040    <example module="pluralizeExample">
20041      <file name="index.html">
20042        <script>
20043          angular.module('pluralizeExample', [])
20044            .controller('ExampleController', ['$scope', function($scope) {
20045              $scope.person1 = 'Igor';
20046              $scope.person2 = 'Misko';
20047              $scope.personCount = 1;
20048            }]);
20049        </script>
20050        <div ng-controller="ExampleController">
20051          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
20052          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
20053          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
20054
20055          <!--- Example with simple pluralization rules for en locale --->
20056          Without Offset:
20057          <ng-pluralize count="personCount"
20058                        when="{'0': 'Nobody is viewing.',
20059                               'one': '1 person is viewing.',
20060                               'other': '{} people are viewing.'}">
20061          </ng-pluralize><br>
20062
20063          <!--- Example with offset --->
20064          With Offset(2):
20065          <ng-pluralize count="personCount" offset=2
20066                        when="{'0': 'Nobody is viewing.',
20067                               '1': '{{person1}} is viewing.',
20068                               '2': '{{person1}} and {{person2}} are viewing.',
20069                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
20070                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20071          </ng-pluralize>
20072        </div>
20073      </file>
20074      <file name="protractor.js" type="protractor">
20075        it('should show correct pluralized string', function() {
20076          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
20077          var withOffset = element.all(by.css('ng-pluralize')).get(1);
20078          var countInput = element(by.model('personCount'));
20079
20080          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
20081          expect(withOffset.getText()).toEqual('Igor is viewing.');
20082
20083          countInput.clear();
20084          countInput.sendKeys('0');
20085
20086          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
20087          expect(withOffset.getText()).toEqual('Nobody is viewing.');
20088
20089          countInput.clear();
20090          countInput.sendKeys('2');
20091
20092          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
20093          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
20094
20095          countInput.clear();
20096          countInput.sendKeys('3');
20097
20098          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
20099          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
20100
20101          countInput.clear();
20102          countInput.sendKeys('4');
20103
20104          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
20105          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
20106        });
20107        it('should show data-bound names', function() {
20108          var withOffset = element.all(by.css('ng-pluralize')).get(1);
20109          var personCount = element(by.model('personCount'));
20110          var person1 = element(by.model('person1'));
20111          var person2 = element(by.model('person2'));
20112          personCount.clear();
20113          personCount.sendKeys('4');
20114          person1.clear();
20115          person1.sendKeys('Di');
20116          person2.clear();
20117          person2.sendKeys('Vojta');
20118          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
20119        });
20120      </file>
20121    </example>
20122 */
20123var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
20124  var BRACE = /{}/g;
20125  return {
20126    restrict: 'EA',
20127    link: function(scope, element, attr) {
20128      var numberExp = attr.count,
20129          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
20130          offset = attr.offset || 0,
20131          whens = scope.$eval(whenExp) || {},
20132          whensExpFns = {},
20133          startSymbol = $interpolate.startSymbol(),
20134          endSymbol = $interpolate.endSymbol(),
20135          isWhen = /^when(Minus)?(.+)$/;
20136
20137      forEach(attr, function(expression, attributeName) {
20138        if (isWhen.test(attributeName)) {
20139          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
20140            element.attr(attr.$attr[attributeName]);
20141        }
20142      });
20143      forEach(whens, function(expression, key) {
20144        whensExpFns[key] =
20145          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
20146            offset + endSymbol));
20147      });
20148
20149      scope.$watch(function ngPluralizeWatch() {
20150        var value = parseFloat(scope.$eval(numberExp));
20151
20152        if (!isNaN(value)) {
20153          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
20154          //check it against pluralization rules in $locale service
20155          if (!(value in whens)) value = $locale.pluralCat(value - offset);
20156           return whensExpFns[value](scope, element, true);
20157        } else {
20158          return '';
20159        }
20160      }, function ngPluralizeWatchAction(newVal) {
20161        element.text(newVal);
20162      });
20163    }
20164  };
20165}];
20166
20167/**
20168 * @ngdoc directive
20169 * @name ngRepeat
20170 *
20171 * @description
20172 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
20173 * instance gets its own scope, where the given loop variable is set to the current collection item,
20174 * and `$index` is set to the item index or key.
20175 *
20176 * Special properties are exposed on the local scope of each template instance, including:
20177 *
20178 * | Variable  | Type            | Details                                                                     |
20179 * |-----------|-----------------|-----------------------------------------------------------------------------|
20180 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
20181 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
20182 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
20183 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
20184 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
20185 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
20186 *
20187 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
20188 * This may be useful when, for instance, nesting ngRepeats.
20189 *
20190 * # Special repeat start and end points
20191 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
20192 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
20193 * 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)
20194 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
20195 *
20196 * The example below makes use of this feature:
20197 * ```html
20198 *   <header ng-repeat-start="item in items">
20199 *     Header {{ item }}
20200 *   </header>
20201 *   <div class="body">
20202 *     Body {{ item }}
20203 *   </div>
20204 *   <footer ng-repeat-end>
20205 *     Footer {{ item }}
20206 *   </footer>
20207 * ```
20208 *
20209 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
20210 * ```html
20211 *   <header>
20212 *     Header A
20213 *   </header>
20214 *   <div class="body">
20215 *     Body A
20216 *   </div>
20217 *   <footer>
20218 *     Footer A
20219 *   </footer>
20220 *   <header>
20221 *     Header B
20222 *   </header>
20223 *   <div class="body">
20224 *     Body B
20225 *   </div>
20226 *   <footer>
20227 *     Footer B
20228 *   </footer>
20229 * ```
20230 *
20231 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
20232 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
20233 *
20234 * @animations
20235 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
20236 *
20237 * **.leave** - when an item is removed from the list or when an item is filtered out
20238 *
20239 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
20240 *
20241 * @element ANY
20242 * @scope
20243 * @priority 1000
20244 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
20245 *   formats are currently supported:
20246 *
20247 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
20248 *     is a scope expression giving the collection to enumerate.
20249 *
20250 *     For example: `album in artist.albums`.
20251 *
20252 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
20253 *     and `expression` is the scope expression giving the collection to enumerate.
20254 *
20255 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
20256 *
20257 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
20258 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
20259 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
20260 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
20261 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
20262 *     before specifying a tracking expression.
20263 *
20264 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
20265 *     will be associated by item identity in the array.
20266 *
20267 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
20268 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
20269 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
20270 *     element in the same way in the DOM.
20271 *
20272 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
20273 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
20274 *     property is same.
20275 *
20276 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
20277 *     to items in conjunction with a tracking expression.
20278 *
20279 * @example
20280 * This example initializes the scope to a list of names and
20281 * then uses `ngRepeat` to display every person:
20282  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20283    <file name="index.html">
20284      <div ng-init="friends = [
20285        {name:'John', age:25, gender:'boy'},
20286        {name:'Jessie', age:30, gender:'girl'},
20287        {name:'Johanna', age:28, gender:'girl'},
20288        {name:'Joy', age:15, gender:'girl'},
20289        {name:'Mary', age:28, gender:'girl'},
20290        {name:'Peter', age:95, gender:'boy'},
20291        {name:'Sebastian', age:50, gender:'boy'},
20292        {name:'Erika', age:27, gender:'girl'},
20293        {name:'Patrick', age:40, gender:'boy'},
20294        {name:'Samantha', age:60, gender:'girl'}
20295      ]">
20296        I have {{friends.length}} friends. They are:
20297        <input type="search" ng-model="q" placeholder="filter friends..." />
20298        <ul class="example-animate-container">
20299          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
20300            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
20301          </li>
20302        </ul>
20303      </div>
20304    </file>
20305    <file name="animations.css">
20306      .example-animate-container {
20307        background:white;
20308        border:1px solid black;
20309        list-style:none;
20310        margin:0;
20311        padding:0 10px;
20312      }
20313
20314      .animate-repeat {
20315        line-height:40px;
20316        list-style:none;
20317        box-sizing:border-box;
20318      }
20319
20320      .animate-repeat.ng-move,
20321      .animate-repeat.ng-enter,
20322      .animate-repeat.ng-leave {
20323        -webkit-transition:all linear 0.5s;
20324        transition:all linear 0.5s;
20325      }
20326
20327      .animate-repeat.ng-leave.ng-leave-active,
20328      .animate-repeat.ng-move,
20329      .animate-repeat.ng-enter {
20330        opacity:0;
20331        max-height:0;
20332      }
20333
20334      .animate-repeat.ng-leave,
20335      .animate-repeat.ng-move.ng-move-active,
20336      .animate-repeat.ng-enter.ng-enter-active {
20337        opacity:1;
20338        max-height:40px;
20339      }
20340    </file>
20341    <file name="protractor.js" type="protractor">
20342      var friends = element.all(by.repeater('friend in friends'));
20343
20344      it('should render initial data set', function() {
20345        expect(friends.count()).toBe(10);
20346        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
20347        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
20348        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
20349        expect(element(by.binding('friends.length')).getText())
20350            .toMatch("I have 10 friends. They are:");
20351      });
20352
20353       it('should update repeater when filter predicate changes', function() {
20354         expect(friends.count()).toBe(10);
20355
20356         element(by.model('q')).sendKeys('ma');
20357
20358         expect(friends.count()).toBe(2);
20359         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
20360         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
20361       });
20362      </file>
20363    </example>
20364 */
20365var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20366  var NG_REMOVED = '$$NG_REMOVED';
20367  var ngRepeatMinErr = minErr('ngRepeat');
20368  return {
20369    transclude: 'element',
20370    priority: 1000,
20371    terminal: true,
20372    $$tlb: true,
20373    link: function($scope, $element, $attr, ctrl, $transclude){
20374        var expression = $attr.ngRepeat;
20375        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
20376          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
20377          lhs, rhs, valueIdentifier, keyIdentifier,
20378          hashFnLocals = {$id: hashKey};
20379
20380        if (!match) {
20381          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
20382            expression);
20383        }
20384
20385        lhs = match[1];
20386        rhs = match[2];
20387        trackByExp = match[3];
20388
20389        if (trackByExp) {
20390          trackByExpGetter = $parse(trackByExp);
20391          trackByIdExpFn = function(key, value, index) {
20392            // assign key, value, and $index to the locals so that they can be used in hash functions
20393            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
20394            hashFnLocals[valueIdentifier] = value;
20395            hashFnLocals.$index = index;
20396            return trackByExpGetter($scope, hashFnLocals);
20397          };
20398        } else {
20399          trackByIdArrayFn = function(key, value) {
20400            return hashKey(value);
20401          };
20402          trackByIdObjFn = function(key) {
20403            return key;
20404          };
20405        }
20406
20407        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
20408        if (!match) {
20409          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
20410                                                                    lhs);
20411        }
20412        valueIdentifier = match[3] || match[1];
20413        keyIdentifier = match[2];
20414
20415        // Store a list of elements from previous run. This is a hash where key is the item from the
20416        // iterator, and the value is objects with following properties.
20417        //   - scope: bound scope
20418        //   - element: previous element.
20419        //   - index: position
20420        var lastBlockMap = {};
20421
20422        //watch props
20423        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
20424          var index, length,
20425              previousNode = $element[0],     // current position of the node
20426              nextNode,
20427              // Same as lastBlockMap but it has the current state. It will become the
20428              // lastBlockMap on the next iteration.
20429              nextBlockMap = {},
20430              arrayLength,
20431              childScope,
20432              key, value, // key/value of iteration
20433              trackById,
20434              trackByIdFn,
20435              collectionKeys,
20436              block,       // last object information {scope, element, id}
20437              nextBlockOrder = [],
20438              elementsToRemove;
20439
20440
20441          if (isArrayLike(collection)) {
20442            collectionKeys = collection;
20443            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
20444          } else {
20445            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
20446            // if object, extract keys, sort them and use to determine order of iteration over obj props
20447            collectionKeys = [];
20448            for (key in collection) {
20449              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
20450                collectionKeys.push(key);
20451              }
20452            }
20453            collectionKeys.sort();
20454          }
20455
20456          arrayLength = collectionKeys.length;
20457
20458          // locate existing items
20459          length = nextBlockOrder.length = collectionKeys.length;
20460          for(index = 0; index < length; index++) {
20461           key = (collection === collectionKeys) ? index : collectionKeys[index];
20462           value = collection[key];
20463           trackById = trackByIdFn(key, value, index);
20464           assertNotHasOwnProperty(trackById, '`track by` id');
20465           if(lastBlockMap.hasOwnProperty(trackById)) {
20466             block = lastBlockMap[trackById];
20467             delete lastBlockMap[trackById];
20468             nextBlockMap[trackById] = block;
20469             nextBlockOrder[index] = block;
20470           } else if (nextBlockMap.hasOwnProperty(trackById)) {
20471             // restore lastBlockMap
20472             forEach(nextBlockOrder, function(block) {
20473               if (block && block.scope) lastBlockMap[block.id] = block;
20474             });
20475             // This is a duplicate and we need to throw an error
20476             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
20477                                                                                                                                                    expression,       trackById);
20478           } else {
20479             // new never before seen block
20480             nextBlockOrder[index] = { id: trackById };
20481             nextBlockMap[trackById] = false;
20482           }
20483         }
20484
20485          // remove existing items
20486          for (key in lastBlockMap) {
20487            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20488            if (lastBlockMap.hasOwnProperty(key)) {
20489              block = lastBlockMap[key];
20490              elementsToRemove = getBlockElements(block.clone);
20491              $animate.leave(elementsToRemove);
20492              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
20493              block.scope.$destroy();
20494            }
20495          }
20496
20497          // we are not using forEach for perf reasons (trying to avoid #call)
20498          for (index = 0, length = collectionKeys.length; index < length; index++) {
20499            key = (collection === collectionKeys) ? index : collectionKeys[index];
20500            value = collection[key];
20501            block = nextBlockOrder[index];
20502            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20503
20504            if (block.scope) {
20505              // if we have already seen this object, then we need to reuse the
20506              // associated scope/element
20507              childScope = block.scope;
20508
20509              nextNode = previousNode;
20510              do {
20511                nextNode = nextNode.nextSibling;
20512              } while(nextNode && nextNode[NG_REMOVED]);
20513
20514              if (getBlockStart(block) != nextNode) {
20515                // existing item which got moved
20516                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20517              }
20518              previousNode = getBlockEnd(block);
20519            } else {
20520              // new item which we don't know about
20521              childScope = $scope.$new();
20522            }
20523
20524            childScope[valueIdentifier] = value;
20525            if (keyIdentifier) childScope[keyIdentifier] = key;
20526            childScope.$index = index;
20527            childScope.$first = (index === 0);
20528            childScope.$last = (index === (arrayLength - 1));
20529            childScope.$middle = !(childScope.$first || childScope.$last);
20530            // jshint bitwise: false
20531            childScope.$odd = !(childScope.$even = (index&1) === 0);
20532            // jshint bitwise: true
20533
20534            if (!block.scope) {
20535              $transclude(childScope, function(clone) {
20536                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20537                $animate.enter(clone, null, jqLite(previousNode));
20538                previousNode = clone;
20539                block.scope = childScope;
20540                // Note: We only need the first/last node of the cloned nodes.
20541                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20542                // by a directive with templateUrl when its template arrives.
20543                block.clone = clone;
20544                nextBlockMap[block.id] = block;
20545              });
20546            }
20547          }
20548          lastBlockMap = nextBlockMap;
20549        });
20550    }
20551  };
20552
20553  function getBlockStart(block) {
20554    return block.clone[0];
20555  }
20556
20557  function getBlockEnd(block) {
20558    return block.clone[block.clone.length - 1];
20559  }
20560}];
20561
20562/**
20563 * @ngdoc directive
20564 * @name ngShow
20565 *
20566 * @description
20567 * The `ngShow` directive shows or hides the given HTML element based on the expression
20568 * provided to the ngShow attribute. The element is shown or hidden by removing or adding
20569 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20570 * in AngularJS and sets the display style to none (using an !important flag).
20571 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20572 *
20573 * ```html
20574 * <!-- when $scope.myValue is truthy (element is visible) -->
20575 * <div ng-show="myValue"></div>
20576 *
20577 * <!-- when $scope.myValue is falsy (element is hidden) -->
20578 * <div ng-show="myValue" class="ng-hide"></div>
20579 * ```
20580 *
20581 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
20582 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20583 * from the element causing the element not to appear hidden.
20584 *
20585 * <div class="alert alert-warning">
20586 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20587 * "f" / "0" / "false" / "no" / "n" / "[]"
20588 * </div>
20589 *
20590 * ## Why is !important used?
20591 *
20592 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20593 * can be easily overridden by heavier selectors. For example, something as simple
20594 * as changing the display style on a HTML list item would make hidden elements appear visible.
20595 * This also becomes a bigger issue when dealing with CSS frameworks.
20596 *
20597 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20598 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20599 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20600 *
20601 * ### Overriding .ng-hide
20602 *
20603 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20604 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20605 * class in CSS:
20606 *
20607 * ```css
20608 * .ng-hide {
20609 *   //this is just another form of hiding an element
20610 *   display:block!important;
20611 *   position:absolute;
20612 *   top:-9999px;
20613 *   left:-9999px;
20614 * }
20615 * ```
20616 *
20617 * By default you don't need to override in CSS anything and the animations will work around the display style.
20618 *
20619 * ## A note about animations with ngShow
20620 *
20621 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20622 * is true and false. This system works like the animation system present with ngClass except that
20623 * you must also include the !important flag to override the display property
20624 * so that you can perform an animation when the element is hidden during the time of the animation.
20625 *
20626 * ```css
20627 * //
20628 * //a working example can be found at the bottom of this page
20629 * //
20630 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20631 *   transition:0.5s linear all;
20632 * }
20633 *
20634 * .my-element.ng-hide-add { ... }
20635 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20636 * .my-element.ng-hide-remove { ... }
20637 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20638 * ```
20639 *
20640 * 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
20641 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20642 *
20643 * @animations
20644 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20645 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
20646 *
20647 * @element ANY
20648 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20649 *     then the element is shown or hidden respectively.
20650 *
20651 * @example
20652  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20653    <file name="index.html">
20654      Click me: <input type="checkbox" ng-model="checked"><br/>
20655      <div>
20656        Show:
20657        <div class="check-element animate-show" ng-show="checked">
20658          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20659        </div>
20660      </div>
20661      <div>
20662        Hide:
20663        <div class="check-element animate-show" ng-hide="checked">
20664          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20665        </div>
20666      </div>
20667    </file>
20668    <file name="glyphicons.css">
20669      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20670    </file>
20671    <file name="animations.css">
20672      .animate-show {
20673        -webkit-transition:all linear 0.5s;
20674        transition:all linear 0.5s;
20675        line-height:20px;
20676        opacity:1;
20677        padding:10px;
20678        border:1px solid black;
20679        background:white;
20680      }
20681
20682      .animate-show.ng-hide {
20683        line-height:0;
20684        opacity:0;
20685        padding:0 10px;
20686      }
20687
20688      .check-element {
20689        padding:10px;
20690        border:1px solid black;
20691        background:white;
20692      }
20693    </file>
20694    <file name="protractor.js" type="protractor">
20695      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20696      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20697
20698      it('should check ng-show / ng-hide', function() {
20699        expect(thumbsUp.isDisplayed()).toBeFalsy();
20700        expect(thumbsDown.isDisplayed()).toBeTruthy();
20701
20702        element(by.model('checked')).click();
20703
20704        expect(thumbsUp.isDisplayed()).toBeTruthy();
20705        expect(thumbsDown.isDisplayed()).toBeFalsy();
20706      });
20707    </file>
20708  </example>
20709 */
20710var ngShowDirective = ['$animate', function($animate) {
20711  return function(scope, element, attr) {
20712    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
20713      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20714    });
20715  };
20716}];
20717
20718
20719/**
20720 * @ngdoc directive
20721 * @name ngHide
20722 *
20723 * @description
20724 * The `ngHide` directive shows or hides the given HTML element based on the expression
20725 * provided to the ngHide attribute. The element is shown or hidden by removing or adding
20726 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20727 * in AngularJS and sets the display style to none (using an !important flag).
20728 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20729 *
20730 * ```html
20731 * <!-- when $scope.myValue is truthy (element is hidden) -->
20732 * <div ng-hide="myValue" class="ng-hide"></div>
20733 *
20734 * <!-- when $scope.myValue is falsy (element is visible) -->
20735 * <div ng-hide="myValue"></div>
20736 * ```
20737 *
20738 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20739 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20740 * from the element causing the element not to appear hidden.
20741 *
20742 * <div class="alert alert-warning">
20743 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20744 * "f" / "0" / "false" / "no" / "n" / "[]"
20745 * </div>
20746 *
20747 * ## Why is !important used?
20748 *
20749 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20750 * can be easily overridden by heavier selectors. For example, something as simple
20751 * as changing the display style on a HTML list item would make hidden elements appear visible.
20752 * This also becomes a bigger issue when dealing with CSS frameworks.
20753 *
20754 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20755 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20756 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20757 *
20758 * ### Overriding .ng-hide
20759 *
20760 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20761 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20762 * class in CSS:
20763 *
20764 * ```css
20765 * .ng-hide {
20766 *   //this is just another form of hiding an element
20767 *   display:block!important;
20768 *   position:absolute;
20769 *   top:-9999px;
20770 *   left:-9999px;
20771 * }
20772 * ```
20773 *
20774 * By default you don't need to override in CSS anything and the animations will work around the display style.
20775 *
20776 * ## A note about animations with ngHide
20777 *
20778 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20779 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
20780 * CSS class is added and removed for you instead of your own CSS class.
20781 *
20782 * ```css
20783 * //
20784 * //a working example can be found at the bottom of this page
20785 * //
20786 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20787 *   transition:0.5s linear all;
20788 * }
20789 *
20790 * .my-element.ng-hide-add { ... }
20791 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20792 * .my-element.ng-hide-remove { ... }
20793 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20794 * ```
20795 *
20796 * 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
20797 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20798 *
20799 * @animations
20800 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20801 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
20802 *
20803 * @element ANY
20804 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
20805 *     the element is shown or hidden respectively.
20806 *
20807 * @example
20808  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20809    <file name="index.html">
20810      Click me: <input type="checkbox" ng-model="checked"><br/>
20811      <div>
20812        Show:
20813        <div class="check-element animate-hide" ng-show="checked">
20814          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20815        </div>
20816      </div>
20817      <div>
20818        Hide:
20819        <div class="check-element animate-hide" ng-hide="checked">
20820          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20821        </div>
20822      </div>
20823    </file>
20824    <file name="glyphicons.css">
20825      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20826    </file>
20827    <file name="animations.css">
20828      .animate-hide {
20829        -webkit-transition:all linear 0.5s;
20830        transition:all linear 0.5s;
20831        line-height:20px;
20832        opacity:1;
20833        padding:10px;
20834        border:1px solid black;
20835        background:white;
20836      }
20837
20838      .animate-hide.ng-hide {
20839        line-height:0;
20840        opacity:0;
20841        padding:0 10px;
20842      }
20843
20844      .check-element {
20845        padding:10px;
20846        border:1px solid black;
20847        background:white;
20848      }
20849    </file>
20850    <file name="protractor.js" type="protractor">
20851      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20852      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20853
20854      it('should check ng-show / ng-hide', function() {
20855        expect(thumbsUp.isDisplayed()).toBeFalsy();
20856        expect(thumbsDown.isDisplayed()).toBeTruthy();
20857
20858        element(by.model('checked')).click();
20859
20860        expect(thumbsUp.isDisplayed()).toBeTruthy();
20861        expect(thumbsDown.isDisplayed()).toBeFalsy();
20862      });
20863    </file>
20864  </example>
20865 */
20866var ngHideDirective = ['$animate', function($animate) {
20867  return function(scope, element, attr) {
20868    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
20869      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
20870    });
20871  };
20872}];
20873
20874/**
20875 * @ngdoc directive
20876 * @name ngStyle
20877 * @restrict AC
20878 *
20879 * @description
20880 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20881 *
20882 * @element ANY
20883 * @param {expression} ngStyle
20884 *
20885 * {@link guide/expression Expression} which evals to an
20886 * object whose keys are CSS style names and values are corresponding values for those CSS
20887 * keys.
20888 *
20889 * Since some CSS style names are not valid keys for an object, they must be quoted.
20890 * See the 'background-color' style in the example below.
20891 *
20892 * @example
20893   <example>
20894     <file name="index.html">
20895        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
20896        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
20897        <input type="button" value="clear" ng-click="myStyle={}">
20898        <br/>
20899        <span ng-style="myStyle">Sample Text</span>
20900        <pre>myStyle={{myStyle}}</pre>
20901     </file>
20902     <file name="style.css">
20903       span {
20904         color: black;
20905       }
20906     </file>
20907     <file name="protractor.js" type="protractor">
20908       var colorSpan = element(by.css('span'));
20909
20910       it('should check ng-style', function() {
20911         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20912         element(by.css('input[value=\'set color\']')).click();
20913         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
20914         element(by.css('input[value=clear]')).click();
20915         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20916       });
20917     </file>
20918   </example>
20919 */
20920var ngStyleDirective = ngDirective(function(scope, element, attr) {
20921  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
20922    if (oldStyles && (newStyles !== oldStyles)) {
20923      forEach(oldStyles, function(val, style) { element.css(style, '');});
20924    }
20925    if (newStyles) element.css(newStyles);
20926  }, true);
20927});
20928
20929/**
20930 * @ngdoc directive
20931 * @name ngSwitch
20932 * @restrict EA
20933 *
20934 * @description
20935 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
20936 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
20937 * as specified in the template.
20938 *
20939 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
20940 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
20941 * matches the value obtained from the evaluated expression. In other words, you define a container element
20942 * (where you place the directive), place an expression on the **`on="..."` attribute**
20943 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
20944 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
20945 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
20946 * attribute is displayed.
20947 *
20948 * <div class="alert alert-info">
20949 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
20950 * as literal string values to match against.
20951 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
20951omeVal"` not against the
20952 * value of the expression `$scope.someVal`.
20953 * </div>
20954
20955 * @animations
20956 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
20957 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
20958 *
20959 * @usage
20960 *
20961 * ```
20962 * <ANY ng-switch="expression">
20963 *   <ANY ng-switch-when="matchValue1">...</ANY>
20964 *   <ANY ng-switch-when="matchValue2">...</ANY>
20965 *   <ANY ng-switch-default>...</ANY>
20966 * </ANY>
20967 * ```
20968 *
20969 *
20970 * @scope
20971 * @priority 800
20972 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
20973 * On child elements add:
20974 *
20975 * * `ngSwitchWhen`: the case statement to match against. If match then this
20976 *   case will be displayed. If the same match appears multiple times, all the
20977 *   elements will be displayed.
20978 * * `ngSwitchDefault`: the default case when no other case match. If there
20979 *   are multiple default cases, all of them will be displayed when no other
20980 *   case match.
20981 *
20982 *
20983 * @example
20984  <example module="switchExample" deps="angular-animate.js" animations="true">
20985    <file name="index.html">
20986      <div ng-controller="ExampleController">
20987        <select ng-model="selection" ng-options="item for item in items">
20988        </select>
20989        <tt>selection={{selection}}</tt>
20990        <hr/>
20991        <div class="animate-switch-container"
20992          ng-switch on="selection">
20993            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
20994            <div class="animate-switch" ng-switch-when="home">Home Span</div>
20995            <div class="animate-switch" ng-switch-default>default</div>
20996        </div>
20997      </div>
20998    </file>
20999    <file name="script.js">
21000      angular.module('switchExample', ['ngAnimate'])
21001        .controller('ExampleController', ['$scope', function($scope) {
21002          $scope.items = ['settings', 'home', 'other'];
21003          $scope.selection = $scope.items[0];
21004        }]);
21005    </file>
21006    <file name="animations.css">
21007      .animate-switch-container {
21008        position:relative;
21009        background:white;
21010        border:1px solid black;
21011        height:40px;
21012        overflow:hidden;
21013      }
21014
21015      .animate-switch {
21016        padding:10px;
21017      }
21018
21019      .animate-switch.ng-animate {
21020        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21021        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21022
21023        position:absolute;
21024        top:0;
21025        left:0;
21026        right:0;
21027        bottom:0;
21028      }
21029
21030      .animate-switch.ng-leave.ng-leave-active,
21031      .animate-switch.ng-enter {
21032        top:-50px;
21033      }
21034      .animate-switch.ng-leave,
21035      .animate-switch.ng-enter.ng-enter-active {
21036        top:0;
21037      }
21038    </file>
21039    <file name="protractor.js" type="protractor">
21040      var switchElem = element(by.css('[ng-switch]'));
21041      var select = element(by.model('selection'));
21042
21043      it('should start in settings', function() {
21044        expect(switchElem.getText()).toMatch(/Settings Div/);
21045      });
21046      it('should change to home', function() {
21047        select.all(by.css('option')).get(1).click();
21048        expect(switchElem.getText()).toMatch(/Home Span/);
21049      });
21050      it('should select default', function() {
21051        select.all(by.css('option')).get(2).click();
21052        expect(switchElem.getText()).toMatch(/default/);
21053      });
21054    </file>
21055  </example>
21056 */
21057var ngSwitchDirective = ['$animate', function($animate) {
21058  return {
21059    restrict: 'EA',
21060    require: 'ngSwitch',
21061
21062    // asks for $scope to fool the BC controller module
21063    controller: ['$scope', function ngSwitchController() {
21064     this.cases = {};
21065    }],
21066    link: function(scope, element, attr, ngSwitchController) {
21067      var watchExpr = attr.ngSwitch || attr.on,
21068          selectedTranscludes = [],
21069          selectedElements = [],
21070          previousElements = [],
21071          selectedScopes = [];
21072
21073      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
21074        var i, ii;
21075        for (i = 0, ii = previousElements.length; i < ii; ++i) {
21076          previousElements[i].remove();
21077        }
21078        previousElements.length = 0;
21079
21080        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
21081          var selected = selectedElements[i];
21082          selectedScopes[i].$destroy();
21083          previousElements[i] = selected;
21084          $animate.leave(selected, function() {
21085            previousElements.splice(i, 1);
21086          });
21087        }
21088
21089        selectedElements.length = 0;
21090        selectedScopes.length = 0;
21091
21092        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
21093          scope.$eval(attr.change);
21094          forEach(selectedTranscludes, function(selectedTransclude) {
21095            var selectedScope = scope.$new();
21096            selectedScopes.push(selectedScope);
21097            selectedTransclude.transclude(selectedScope, function(caseElement) {
21098              var anchor = selectedTransclude.element;
21099
21100              selectedElements.push(caseElement);
21101              $animate.enter(caseElement, anchor.parent(), anchor);
21102            });
21103          });
21104        }
21105      });
21106    }
21107  };
21108}];
21109
21110var ngSwitchWhenDirective = ngDirective({
21111  transclude: 'element',
21112  priority: 800,
21113  require: '^ngSwitch',
21114  link: function(scope, element, attrs, ctrl, $transclude) {
21115    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
21116    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
21117  }
21118});
21119
21120var ngSwitchDefaultDirective = ngDirective({
21121  transclude: 'element',
21122  priority: 800,
21123  require: '^ngSwitch',
21124  link: function(scope, element, attr, ctrl, $transclude) {
21125    ctrl.cases['?'] = (ctrl.cases['?'] || []);
21126    ctrl.cases['?'].push({ transclude: $transclude, element: element });
21127   }
21128});
21129
21130/**
21131 * @ngdoc directive
21132 * @name ngTransclude
21133 * @restrict AC
21134 *
21135 * @description
21136 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
21137 *
21138 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
21139 *
21140 * @element ANY
21141 *
21142 * @example
21143   <example module="transcludeExample">
21144     <file name="index.html">
21145       <script>
21146         angular.module('transcludeExample', [])
21147          .directive('pane', function(){
21148             return {
21149               restrict: 'E',
21150               transclude: true,
21151               scope: { title:'@' },
21152               template: '<div style="border: 1px solid black;">
21152' +
21153                           '<div style="background-color: gray">{{title}}</div>' +
21154                           '<div ng-transclude></div>' +
21155                         '</div>'
21156             };
21157         })
21158         .controller('ExampleController', ['$scope', function($scope) {
21159           $scope.title = 'Lorem Ipsum';
21160           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
21161         }]);
21162       </script>
21163       <div ng-controller="ExampleController">
21164         <input ng-model="title"><br>
21165         <textarea ng-model="text"></textarea> <br/>
21166         <pane title="{{title}}">{{text}}</pane>
21167       </div>
21168     </file>
21169     <file name="protractor.js" type="protractor">
21170        it('should have transcluded', function() {
21171          var titleElement = element(by.model('title'));
21172          titleElement.clear();
21173          titleElement.sendKeys('TITLE');
21174          var textElement = element(by.model('text'));
21175          textElement.clear();
21176          textElement.sendKeys('TEXT');
21177          expect(element(by.binding('title')).getText()).toEqual('TITLE');
21178          expect(element(by.binding('text')).getText()).toEqual('TEXT');
21179        });
21180     </file>
21181   </example>
21182 *
21183 */
21184var ngTranscludeDirective = ngDirective({
21185  link: function($scope, $element, $attrs, controller, $transclude) {
21186    if (!$transclude) {
21187      throw minErr('ngTransclude')('orphan',
21188       'Illegal use of ngTransclude directive in the template! ' +
21189       'No parent directive that requires a transclusion found. ' +
21190       'Element: {0}',
21191       startingTag($element));
21192    }
21193
21194    $transclude(function(clone) {
21195      $element.empty();
21196      $element.append(clone);
21197    });
21198  }
21199});
21200
21201/**
21202 * @ngdoc directive
21203 * @name script
21204 * @restrict E
21205 *
21206 * @description
21207 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
21208 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
21209 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
21210 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
21211 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
21212 *
21213 * @param {string} type Must be set to `'text/ng-template'`.
21214 * @param {string} id Cache name of the template.
21215 *
21216 * @example
21217  <example>
21218    <file name="index.html">
21219      <script type="text/ng-template" id="/tpl.html">
21220        Content of the template.
21221      </script>
21222
21223      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
21224      <div id="tpl-content" ng-include src="currentTpl"></div>
21225    </file>
21226    <file name="protractor.js" type="protractor">
21227      it('should load template defined inside script tag', function() {
21228        element(by.css('#tpl-link')).click();
21229        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
21230      });
21231    </file>
21232  </example>
21233 */
21234var scriptDirective = ['$templateCache', function($templateCache) {
21235  return {
21236    restrict: 'E',
21237    terminal: true,
21238    compile: function(element, attr) {
21239      if (attr.type == 'text/ng-template') {
21240        var templateUrl = attr.id,
21241            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
21242            text = element[0].text;
21243
21244        $templateCache.put(templateUrl, text);
21245      }
21246    }
21247  };
21248}];
21249
21250var ngOptionsMinErr = minErr('ngOptions');
21251/**
21252 * @ngdoc directive
21253 * @name select
21254 * @restrict E
21255 *
21256 * @description
21257 * HTML `SELECT` element with angular data-binding.
21258 *
21259 * # `ngOptions`
21260 *
21261 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
21262 * elements for the `<select>` element using the array or object obtained by evaluating the
21263 * `ngOptions` comprehension_expression.
21264 *
21265 * When an item in the `<select>` menu is selected, the array element or object property
21266 * represented by the selected option will be bound to the model identified by the `ngModel`
21267 * directive.
21268 *
21269 * <div class="alert alert-warning">
21270 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
21271 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
21272 * </div>
21273 *
21274 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
21275 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
21276 * option. See example below for demonstration.
21277 *
21278 * <div class="alert alert-warning">
21279 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
21280 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
21281 * `select` model to be bound to a non-string value. This is because an option element can only
21282 * be bound to string values at present.
21283 * </div>
21284 *
21285 * @param {string} ngModel Assignable angular expression to data-bind to.
21286 * @param {string=} name Property name of the form under which the control is published.
21287 * @param {string=} required The control is considered valid only if value is entered.
21288 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21289 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21290 *    `required` when you want to data-bind to the `required` attribute.
21291 * @param {comprehension_expression=} ngOptions in one of the following forms:
21292 *
21293 *   * for array data sources:
21294 *     * `label` **`for`** `value` **`in`** `array`
21295 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
21296 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
21297 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
21298 *   * for object data sources:
21299 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21300 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21301 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
21302 *     * `select` **`as`** `label` **`group by`** `group`
21303 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
21304 *
21305 * Where:
21306 *
21307 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
21308 *   * `value`: local variable which will refer to each item in the `array` or each property value
21309 *      of `object` during iteration.
21310 *   * `key`: local variable which will refer to a property name in `object` during iteration.
21311 *   * `label`: The result of this expression will be the label for `<option>` element. The
21312 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
21313 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
21314 *      element. If not specified, `select` expression will default to `value`.
21315 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
21316 *      DOM element.
21317 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
21318 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
21319 *     `value` variable (e.g. `value.propertyName`).
21320 *
21321 * @example
21322    <example module="selectExample">
21323      <file name="index.html">
21324        <script>
21325        angular.module('selectExample', [])
21326          .controller('ExampleController', ['$scope', function($scope) {
21327            $scope.colors = [
21328              {name:'black', shade:'dark'},
21329              {name:'white', shade:'light'},
21330              {name:'red', shade:'dark'},
21331              {name:'blue', shade:'dark'},
21332              {name:'yellow', shade:'light'}
21333            ];
21334            $scope.myColor = $scope.colors[2]; // red
21335          }]);
21336        </script>
21337        <div ng-controller="ExampleController">
21338          <ul>
21339            <li ng-repeat="color in colors">
21340              Name: <input ng-model="color.name">
21341              [<a href ng-click="colors.splice($index, 1)">X</a>]
21342            </li>
21343            <li>
21344              [<a href ng-click="colors.push({})">add</a>]
21345            </li>
21346          </ul>
21347          <hr/>
21348          Color (null not allowed):
21349          <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
21350
21351          Color (null allowed):
21352          <span  class="nullable">
21353            <select ng-model="myColor" ng-options="color.name for color in colors">
21354              <option value="">-- choose color --</option>
21355            </select>
21356          </span><br/>
21357
21358          Color grouped by shade:
21359          <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
21360          </select><br/>
21361
21362
21363          Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
21364          <hr/>
21365          Currently selected: {{ {selected_color:myColor}  }}
21366          <div style="border:solid 1px black; height:20px"
21367               ng-style="{'background-color':myColor.name}">
21368          </div>
21369        </div>
21370      </file>
21371      <file name="protractor.js" type="protractor">
21372         it('should check ng-options', function() {
21373           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
21374           element.all(by.model('myColor')).first().click();
21375           element.all(by.css('select[ng-model="myColor"] option')).first().click();
21376           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
21377           element(by.css('.nullable select[ng-model="myColor"]')).click();
21378           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
21379           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
21380         });
21381      </file>
21382    </example>
21383 */
21384
21385var ngOptionsDirective = valueFn({ terminal: true });
21386// jshint maxlen: false
21387var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
21388                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
21389  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]+?))?$/,
21390      nullModelCtrl = {$setViewValue: noop};
21391// jshint maxlen: 100
21392
21393  return {
21394    restrict: 'E',
21395    require: ['select', '?ngModel'],
21396    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
21397      var self = this,
21398          optionsMap = {},
21399          ngModelCtrl = nullModelCtrl,
21400          nullOption,
21401          unknownOption;
21402
21403
21404      self.databound = $attrs.ngModel;
21405
21406
21407      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
21408        ngModelCtrl = ngModelCtrl_;
21409        nullOption = nullOption_;
21410        unknownOption = unknownOption_;
21411      };
21412
21413
21414      self.addOption = function(value) {
21415        assertNotHasOwnProperty(value, '"option value"');
21416        optionsMap[value] = true;
21417
21418        if (ngModelCtrl.$viewValue == value) {
21419          $element.val(value);
21420          if (unknownOption.parent()) unknownOption.remove();
21421        }
21422      };
21423
21424
21425      self.removeOption = function(value) {
21426        if (this.hasOption(value)) {
21427          delete optionsMap[value];
21428          if (ngModelCtrl.$viewValue == value) {
21429            this.renderUnknownOption(value);
21430          }
21431        }
21432      };
21433
21434
21435      self.renderUnknownOption = function(val) {
21436        var unknownVal = '? ' + hashKey(val) + ' ?';
21437        unknownOption.val(unknownVal);
21438        $element.prepend(unknownOption);
21439        $element.val(unknownVal);
21440        unknownOption.prop('selected', true); // needed for IE
21441      };
21442
21443
21444      self.hasOption = function(value) {
21445        return optionsMap.hasOwnProperty(value);
21446      };
21447
21448      $scope.$on('$destroy', function() {
21449        // disable unknown option so that we don't do work when the whole select is being destroyed
21450        self.renderUnknownOption = noop;
21451      });
21452    }],
21453
21454    link: function(scope, element, attr, ctrls) {
21455      // if ngModel is not defined, we don't need to do anything
21456      if (!ctrls[1]) return;
21457
21458      var selectCtrl = ctrls[0],
21459          ngModelCtrl = ctrls[1],
21460          multiple = attr.multiple,
21461          optionsExp = attr.ngOptions,
21462          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21463          emptyOption,
21464          // we can't just jqLite('<option>') since jqLite is not smart enough
21465          // to create it in <select> and IE barfs otherwise.
21466          optionTemplate = jqLite(document.createElement('option')),
21467          optGroupTemplate =jqLite(document.createElement('optgroup')),
21468          unknownOption = optionTemplate.clone();
21469
21470      // find "null" option
21471      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21472        if (children[i].value === '') {
21473          emptyOption = nullOption = children.eq(i);
21474          break;
21475        }
21476      }
21477
21478      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21479
21480      // required validator
21481      if (multiple) {
21482        ngModelCtrl.$isEmpty = function(value) {
21483          return !value || value.length === 0;
21484        };
21485      }
21486
21487      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21488      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21489      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21490
21491
21492      ////////////////////////////
21493
21494
21495
21496      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21497        ngModelCtrl.$render = function() {
21498          var viewValue = ngModelCtrl.$viewValue;
21499
21500          if (selectCtrl.hasOption(viewValue)) {
21501            if (unknownOption.parent()) unknownOption.remove();
21502            selectElement.val(viewValue);
21503            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21504          } else {
21505            if (isUndefined(viewValue) && emptyOption) {
21506              selectElement.val('');
21507            } else {
21508              selectCtrl.renderUnknownOption(viewValue);
21509            }
21510          }
21511        };
21512
21513        selectElement.on('change', function() {
21514          scope.$apply(function() {
21515            if (unknownOption.parent()) unknownOption.remove();
21516            ngModelCtrl.$setViewValue(selectElement.val());
21517          });
21518        });
21519      }
21520
21521      function setupAsMultiple(scope, selectElement, ctrl) {
21522        var lastView;
21523        ctrl.$render = function() {
21524          var items = new HashMap(ctrl.$viewValue);
21525          forEach(selectElement.find('option'), function(option) {
21526            option.selected = isDefined(items.get(option.value));
21527          });
21528        };
21529
21530        // we have to do it on each watch since ngModel watches reference, but
21531        // we need to work of an array, so we need to see if anything was inserted/removed
21532        scope.$watch(function selectMultipleWatch() {
21533          if (!equals(lastView, ctrl.$viewValue)) {
21534            lastView = shallowCopy(ctrl.$viewValue);
21535            ctrl.$render();
21536          }
21537        });
21538
21539        selectElement.on('change', function() {
21540          scope.$apply(function() {
21541            var array = [];
21542            forEach(selectElement.find('option'), function(option) {
21543              if (option.selected) {
21544                array.push(option.value);
21545              }
21546            });
21547            ctrl.$setViewValue(array);
21548          });
21549        });
21550      }
21551
21552      function setupAsOptions(scope, selectElement, ctrl) {
21553        var match;
21554
21555        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21556          throw ngOptionsMinErr('iexp',
21557            "Expected expression in form of " +
21558            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21559            " but got '{0}'. Element: {1}",
21560            optionsExp, startingTag(selectElement));
21561        }
21562
21563        var displayFn = $parse(match[2] || match[1]),
21564            valueName = match[4] || match[6],
21565            keyName = match[5],
21566            groupByFn = $parse(match[3] || ''),
21567            valueFn = $parse(match[2] ? match[1] : valueName),
21568            valuesFn = $parse(match[7]),
21569            track = match[8],
21570            trackFn = track ? $parse(match[8]) : null,
21571            // This is an array of array of existing option groups in DOM.
21572            // We try to reuse these if possible
21573            // - optionGroupsCache[0] is the options with no option group
21574            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21575            optionGroupsCache = [[{element: selectElement, label:''}]];
21576
21577        if (nullOption) {
21578          // compile the element since there might be bindings in it
21579          $compile(nullOption)(scope);
21580
21581          // remove the class, which is added automatically because we recompile the element and it
21582          // becomes the compilation root
21583          nullOption.removeClass('ng-scope');
21584
21585          // we need to remove it before calling selectElement.empty() because otherwise IE will
21586          // remove the label from the element. wtf?
21587          nullOption.remove();
21588        }
21589
21590        // clear contents, we'll add what's needed based on the model
21591        selectElement.empty();
21592
21593        selectElement.on('change', function() {
21594          scope.$apply(function() {
21595            var optionGroup,
21596                collection = valuesFn(scope) || [],
21597                locals = {},
21598                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21599
21600            if (multiple) {
21601              value = [];
21602              for (groupIndex = 0, groupLength = optionGroupsCache.length;
21603                   groupIndex < groupLength;
21604                   groupIndex++) {
21605                // list of options for that group. (first item has the parent)
21606                optionGroup = optionGroupsCache[groupIndex];
21607
21608                for(index = 1, length = optionGroup.length; index < length; index++) {
21609                  if ((optionElement = optionGroup[index].element)[0].selected) {
21610                    key = optionElement.val();
21611                    if (keyName) locals[keyName] = key;
21612                    if (trackFn) {
21613                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21614                        locals[valueName] = collection[trackIndex];
21615                        if (trackFn(scope, locals) == key) break;
21616                      }
21617                    } else {
21618                      locals[valueName] = collection[key];
21619                    }
21620                    value.push(valueFn(scope, locals));
21621                  }
21622                }
21623              }
21624            } else {
21625              key = selectElement.val();
21626              if (key == '?') {
21627                value = undefined;
21628              } else if (key === ''){
21629                value = null;
21630              } else {
21631                if (trackFn) {
21632                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21633                    locals[valueName] = collection[trackIndex];
21634                    if (trackFn(scope, locals) == key) {
21635                      value = valueFn(scope, locals);
21636                      break;
21637                    }
21638                  }
21639                } else {
21640                  locals[valueName] = collection[key];
21641                  if (keyName) locals[keyName] = key;
21642                  value = valueFn(scope, locals);
21643                }
21644              }
21645            }
21646            ctrl.$setViewValue(value);
21647            render();
21648          });
21649        });
21650
21651        ctrl.$render = render;
21652
21653        scope.$watchCollection(valuesFn, render);
21654        if ( multiple ) {
21655          scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
21656        }
21657
21658        function getSelectedSet() {
21659          var selectedSet = false;
21660          if (multiple) {
21661            var modelValue = ctrl.$modelValue;
21662            if (trackFn && isArray(modelValue)) {
21663              selectedSet = new HashMap([]);
21664              var locals = {};
21665              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21666                locals[valueName] = modelValue[trackIndex];
21667                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21668              }
21669            } else {
21670              selectedSet = new HashMap(modelValue);
21671            }
21672          }
21673          return selectedSet;
21674        }
21675
21676
21677        function render() {
21678              // Temporary location for the option groups before we render them
21679          var optionGroups = {'':[]},
21680              optionGroupNames = [''],
21681              optionGroupName,
21682              optionGroup,
21683              option,
21684              existingParent, existingOptions, existingOption,
21685              modelValue = ctrl.$modelValue,
21686              values = valuesFn(scope) || [],
21687              keys = keyName ? sortedKeys(values) : values,
21688              key,
21689              groupLength, length,
21690              groupIndex, index,
21691              locals = {},
21692              selected,
21693              selectedSet = getSelectedSet(),
21694              lastElement,
21695              element,
21696              label;
21697
21698
21699          // We now build up the list of options we need (we merge later)
21700          for (index = 0; length = keys.length, index < length; index++) {
21701
21702            key = index;
21703            if (keyName) {
21704              key = keys[index];
21705              if ( key.charAt(0) === '$' ) continue;
21706              locals[keyName] = key;
21707            }
21708
21709            locals[valueName] = values[key];
21710
21711            optionGroupName = groupByFn(scope, locals) || '';
21712            if (!(optionGroup = optionGroups[optionGroupName])) {
21713              optionGroup = optionGroups[optionGroupName] = [];
21714              optionGroupNames.push(optionGroupName);
21715            }
21716            if (multiple) {
21717              selected = isDefined(
21718                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21719              );
21720            } else {
21721              if (trackFn) {
21722                var modelCast = {};
21723                modelCast[valueName] = modelValue;
21724                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21725              } else {
21726                selected = modelValue === valueFn(scope, locals);
21727              }
21728              selectedSet = selectedSet || selected; // see if at least one item is selected
21729            }
21730            label = displayFn(scope, locals); // what will be seen by the user
21731
21732            // doing displayFn(scope, locals) || '' overwrites zero values
21733            label = isDefined(label) ? label : '';
21734            optionGroup.push({
21735              // either the index into array or key from object
21736              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
21737              label: label,
21738              selected: selected                   // determine if we should be selected
21739            });
21740          }
21741          if (!multiple) {
21742            if (nullOption || modelValue === null) {
21743              // insert null option if we have a placeholder, or the model is null
21744              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
21745            } else if (!selectedSet) {
21746              // option could not be found, we have to insert the undefined item
21747              optionGroups[''].unshift({id:'?', label:'', selected:true});
21748            }
21749          }
21750
21751          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
21752          for (groupIndex = 0, groupLength = optionGroupNames.length;
21753               groupIndex < groupLength;
21754               groupIndex++) {
21755            // current option group name or '' if no group
21756            optionGroupName = optionGroupNames[groupIndex];
21757
21758            // list of options for that group. (first item has the parent)
21759            optionGroup = optionGroups[optionGroupName];
21760
21761            if (optionGroupsCache.length <= groupIndex) {
21762              // we need to grow the optionGroups
21763              existingParent = {
21764                element: optGroupTemplate.clone().attr('label', optionGroupName),
21765                label: optionGroup.label
21766              };
21767              existingOptions = [existingParent];
21768              optionGroupsCache.push(existingOptions);
21769              selectElement.append(existingParent.element);
21770            } else {
21771              existingOptions = optionGroupsCache[groupIndex];
21772              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
21773
21774              // update the OPTGROUP label if not the same.
21775              if (existingParent.label != optionGroupName) {
21776                existingParent.element.attr('label', existingParent.label = optionGroupName);
21777              }
21778            }
21779
21780            lastElement = null;  // start at the beginning
21781            for(index = 0, length = optionGroup.length; index < length; index++) {
21782              option = optionGroup[index];
21783              if ((existingOption = existingOptions[index+1])) {
21784                // reuse elements
21785                lastElement = existingOption.element;
21786                if (existingOption.label !== option.label) {
21787                  lastElement.text(existingOption.label = option.label);
21788                }
21789                if (existingOption.id !== option.id) {
21790                  lastElement.val(existingOption.id = option.id);
21791                }
21792                // lastElement.prop('selected') provided by jQuery has side-effects
21793                if (lastElement[0].selected !== option.selected) {
21794                  lastElement.prop('selected', (existingOption.selected = option.selected));
21795                  if (msie) {
21796                    // See #7692
21797                    // The selected item wouldn't visually update on IE without this.
21798                    // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
21799                    lastElement.prop('selected', existingOption.selected);
21800                  }
21801                }
21802              } else {
21803                // grow elements
21804
21805                // if it's a null option
21806                if (option.id === '' && nullOption) {
21807                  // put back the pre-compiled element
21808                  element = nullOption;
21809                } else {
21810                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
21811                  // in this version of jQuery on some browser the .text() returns a string
21812                  // rather then the element.
21813                  (element = optionTemplate.clone())
21814                      .val(option.id)
21815                      .prop('selected', option.selected)
21816                      .attr('selected', option.selected)
21817                      .text(option.label);
21818                }
21819
21820                existingOptions.push(existingOption = {
21821                    element: element,
21822                    label: option.label,
21823                    id: option.id,
21824                    selected: option.selected
21825                });
21826                if (lastElement) {
21827                  lastElement.after(element);
21828                } else {
21829                  existingParent.element.append(element);
21830                }
21831                lastElement = element;
21832              }
21833            }
21834            // remove any excessive OPTIONs in a group
21835            index++; // increment since the existingOptions[0] is parent element not OPTION
21836            while(existingOptions.length > index) {
21837              existingOptions.pop().element.remove();
21838            }
21839          }
21840          // remove any excessive OPTGROUPs from select
21841          while(optionGroupsCache.length > groupIndex) {
21842            optionGroupsCache.pop()[0].element.remove();
21843          }
21844        }
21845      }
21846    }
21847  };
21848}];
21849
21850var optionDirective = ['$interpolate', function($interpolate) {
21851  var nullSelectCtrl = {
21852    addOption: noop,
21853    removeOption: noop
21854  };
21855
21856  return {
21857    restrict: 'E',
21858    priority: 100,
21859    compile: function(element, attr) {
21860      if (isUndefined(attr.value)) {
21861        var interpolateFn = $interpolate(element.text(), true);
21862        if (!interpolateFn) {
21863          attr.$set('value', element.text());
21864        }
21865      }
21866
21867      return function (scope, element, attr) {
21868        var selectCtrlName = '$selectController',
21869            parent = element.parent(),
21870            selectCtrl = parent.data(selectCtrlName) ||
21871              parent.parent().data(selectCtrlName); // in case we are in optgroup
21872
21873        if (selectCtrl && selectCtrl.databound) {
21874          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
21875          // We don't want the view to drive the initialization of the model anyway.
21876          element.prop('selected', false);
21877        } else {
21878          selectCtrl = nullSelectCtrl;
21879        }
21880
21881        if (interpolateFn) {
21882          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
21883            attr.$set('value', newVal);
21884            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
21885            selectCtrl.addOption(newVal);
21886          });
21887        } else {
21888          selectCtrl.addOption(attr.value);
21889        }
21890
21891        element.on('$destroy', function() {
21892          selectCtrl.removeOption(attr.value);
21893        });
21894      };
21895    }
21896  };
21897}];
21898
21899var styleDirective = valueFn({
21900  restrict: 'E',
21901  terminal: true
21902});
21903
21904  if (window.angular.bootstrap) {
21905    //AngularJS is already loaded, so we can return here...
21906    console.log('WARNING: Tried to load angular more than once.');
21907    return;
21908  }
21909
21910  //try to bind to jquery now so that one can write angular.element().read()
21911  //but we will rebind on bootstrap again.
21912  bindJQuery();
21913
21914  publishExternalAPI(angular);
21915
21916  jqLite(document).ready(function() {
21917    angularInit(document, bootstrap);
21918  });
21919
21920})(window, document);
21921
21922!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.