PageSourceSearch

https://borm.es/bower_components/angular/angular.js

js borm.es collected 2026-10-02 05:23:36 UTC 791,536 bytes, 22,197 lines download raw bytes

1/**
2 * @license AngularJS v1.2.32
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.32/' +
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
238    msie,             // holds major version number for IE, or NaN if UA is not IE.
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 own enumerable 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  * @param {*} value to be returned.
486  * @returns {*} the value passed in.
487 */
488function identity($) {return $;}
489identity.$inject = [];
490
491
492function valueFn(value) {return function() {return value;};}
493
494/**
495 * @ngdoc function
496 * @name angular.isUndefined
497 * @module ng
498 * @kind function
499 *
500 * @description
501 * Determines if a reference is undefined.
502 *
503 * @param {*} value Reference to check.
504 * @returns {boolean} True if `value` is undefined.
505 */
506function isUndefined(value){return typeof value === 'undefined';}
507
508
509/**
510 * @ngdoc function
511 * @name angular.isDefined
512 * @module ng
513 * @kind function
514 *
515 * @description
516 * Determines if a reference is defined.
517 *
518 * @param {*} value Reference to check.
519 * @returns {boolean} True if `value` is defined.
520 */
521function isDefined(value){return typeof value !== 'undefined';}
522
523
524/**
525 * @ngdoc function
526 * @name angular.isObject
527 * @module ng
528 * @kind function
529 *
530 * @description
531 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
532 * considered to be objects. Note that JavaScript arrays are objects.
533 *
534 * @param {*} value Reference to check.
535 * @returns {boolean} True if `value` is an `Object` but not `null`.
536 */
537function isObject(value){return value != null && typeof value === 'object';}
538
539
540/**
541 * @ngdoc function
542 * @name angular.isString
543 * @module ng
544 * @kind function
545 *
546 * @description
547 * Determines if a reference is a `String`.
548 *
549 * @param {*} value Reference to check.
550 * @returns {boolean} True if `value` is a `String`.
551 */
552function isString(value){return typeof value === 'string';}
553
554
555/**
556 * @ngdoc function
557 * @name angular.isNumber
558 * @module ng
559 * @kind function
560 *
561 * @description
562 * Determines if a reference is a `Number`.
563 *
564 * @param {*} value Reference to check.
565 * @returns {boolean} True if `value` is a `Number`.
566 */
567function isNumber(value){return typeof value === 'number';}
568
569
570/**
571 * @ngdoc function
572 * @name angular.isDate
573 * @module ng
574 * @kind function
575 *
576 * @description
577 * Determines if a value is a date.
578 *
579 * @param {*} value Reference to check.
580 * @returns {boolean} True if `value` is a `Date`.
581 */
582function isDate(value) {
583  return toString.call(value) === '[object Date]';
584}
585
586
587/**
588 * @ngdoc function
589 * @name angular.isArray
590 * @module ng
591 * @kind function
592 *
593 * @description
594 * Determines if a reference is an `Array`.
595 *
596 * @param {*} value Reference to check.
597 * @returns {boolean} True if `value` is an `Array`.
598 */
599var isArray = (function() {
600  if (!isFunction(Array.isArray)) {
601    return function(value) {
602      return toString.call(value) === '[object Array]';
603    };
604  }
605  return Array.isArray;
606})();
607
608/**
609 * @ngdoc function
610 * @name angular.isFunction
611 * @module ng
612 * @kind function
613 *
614 * @description
615 * Determines if a reference is a `Function`.
616 *
617 * @param {*} value Reference to check.
618 * @returns {boolean} True if `value` is a `Function`.
619 */
620function isFunction(value){return typeof value === 'function';}
621
622
623/**
624 * Determines if a value is a regular expression object.
625 *
626 * @private
627 * @param {*} value Reference to check.
628 * @returns {boolean} True if `value` is a `RegExp`.
629 */
630function isRegExp(value) {
631  return toString.call(value) === '[object RegExp]';
632}
633
634
635/**
636 * Checks if `obj` is a window object.
637 *
638 * @private
639 * @param {*} obj Object to check
640 * @returns {boolean} True if `obj` is a window obj.
641 */
642function isWindow(obj) {
643  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
644}
645
646
647function isScope(obj) {
648  return obj && obj.$evalAsync && obj.$watch;
649}
650
651
652function isFile(obj) {
653  return toString.call(obj) === '[object File]';
654}
655
656
657function isBlob(obj) {
658  return toString.call(obj) === '[object Blob]';
659}
660
661
662function isBoolean(value) {
663  return typeof value === 'boolean';
664}
665
666
667function isPromiseLike(obj) {
668  return obj && isFunction(obj.then);
669}
670
671
672var trim = (function() {
673  // native trim is way faster: http://jsperf.com/angular-trim-test
674  // but IE doesn't have it... :-(
675  // TODO: we should move this into IE/ES5 polyfill
676  if (!String.prototype.trim) {
677    return function(value) {
678      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
679    };
680  }
681  return function(value) {
682    return isString(value) ? value.trim() : value;
683  };
684})();
685
686
687/**
688 * @ngdoc function
689 * @name angular.isElement
690 * @module ng
691 * @kind function
692 *
693 * @description
694 * Determines if a reference is a DOM element (or wrapped jQuery element).
695 *
696 * @param {*} value Reference to check.
697 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
698 */
699function isElement(node) {
700  return !!(node &&
701    (node.nodeName  // we are a direct element
702    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
703}
704
705/**
706 * @param str 'key1,key2,...'
707 * @returns {object} in the form of {key1:true, key2:true, ...}
708 */
709function makeMap(str) {
710  var obj = {}, items = str.split(","), i;
711  for ( i = 0; i < items.length; i++ )
712    obj[ items[i] ] = true;
713  return obj;
714}
715
716
717if (msie < 9) {
718  nodeName_ = function(element) {
719    element = element.nodeName ? element : element[0];
720    return (element.scopeName && element.scopeName != 'HTML')
721      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
722  };
723} else {
724  nodeName_ = function(element) {
725    return element.nodeName ? element.nodeName : element[0].nodeName;
726  };
727}
728
729
730function map(obj, iterator, context) {
731  var results = [];
732  forEach(obj, function(value, index, list) {
733    results.push(iterator.call(context, value, index, list));
734  });
735  return results;
736}
737
738
739/**
740 * @description
741 * Determines the number of elements in an array, the number of properties an object has, or
742 * the length of a string.
743 *
744 * Note: This function is used to augment the Object type in Angular expressions. See
745 * {@link angular.Object} for more information about Angular arrays.
746 *
747 * @param {Object|Array|string} obj Object, array, or string to inspect.
748 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
749 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
750 */
751function size(obj, ownPropsOnly) {
752  var count = 0, key;
753
754  if (isArray(obj) || isString(obj)) {
755    return obj.length;
756  } else if (isObject(obj)) {
757    for (key in obj)
758      if (!ownPropsOnly || obj.hasOwnProperty(key))
759        count++;
760  }
761
762  return count;
763}
764
765
766function includes(array, obj) {
767  return indexOf(array, obj) != -1;
768}
769
770function indexOf(array, obj) {
771  if (array.indexOf) return array.indexOf(obj);
772
773  for (var i = 0; i < array.length; i++) {
774    if (obj === array[i]) return i;
775  }
776  return -1;
777}
778
779function arrayRemove(array, value) {
780  var index = indexOf(array, value);
781  if (index >=0)
782    array.splice(index, 1);
783  return value;
784}
785
786function isLeafNode (node) {
787  if (node) {
788    switch (node.nodeName) {
789    case "OPTION":
790    case "PRE":
791    case "TITLE":
792      return true;
793    }
794  }
795  return false;
796}
797
798/**
799 * @ngdoc function
800 * @name angular.copy
801 * @module ng
802 * @kind function
803 *
804 * @description
805 * Creates a deep copy of `source`, which should be an object or an array.
806 *
807 * * If no destination is supplied, a copy of the object or array is created.
808 * * If a destination is provided, all of its elements (for array) or properties (for objects)
809 *   are deleted and then all elements/properties from the source are copied to it.
810 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
811 * * If `source` is identical to 'destination' an exception will be thrown.
812 *
813 * @param {*} source The source that will be used to make a copy.
814 *                   Can be any type, including primitives, `null`, and `undefined`.
815 * @param {(Object|Array)=} destination Destination into which the source is copied. If
816 *     provided, must be of the same type as `source`.
817 * @returns {*} The copy or updated `destination`, if `destination` was specified.
818 *
819 * @example
820 <example module="copyExample">
821 <file name="index.html">
822 <div ng-controller="ExampleController">
823 <form novalidate class="simple-form">
824 Name: <input type="text" ng-model="user.name" /><br />
825 E-mail: <input type="email" ng-model="user.email" /><br />
826 Gender: <input type="radio" ng-model="user.gender" value="male" />male
827 <input type="radio" ng-model="user.gender" value="female" />female<br />
828 <button ng-click="reset()">RESET</button>
829 <button ng-click="update(user)">SAVE</button>
830 </form>
831 <pre>form = {{user | json}}</pre>
832 <pre>master = {{master | json}}</pre>
833 </div>
834
835 <script>
836  angular.module('copyExample', [])
837    .controller('ExampleController', ['$scope', function($scope) {
838      $scope.master= {};
839
840      $scope.update = function(user) {
841        // Example with 1 argument
842        $scope.master= angular.copy(user);
843      };
844
845      $scope.reset = function() {
846        // Example with 2 arguments
847        angular.copy($scope.master, $scope.user);
848      };
849
850      $scope.reset();
851    }]);
852 </script>
853 </file>
854 </example>
855 */
856function copy(source, destination, stackSource, stackDest) {
857  if (isWindow(source) || isScope(source)) {
858    throw ngMinErr('cpws',
859      "Can't copy! Making copies of Window or Scope instances is not supported.");
860  }
861
862  if (!destination) {
863    destination = source;
864    if (source) {
865      if (isArray(source)) {
866        destination = copy(source, [], stackSource, stackDest);
867      } else if (isDate(source)) {
868        destination = new Date(source.getTime());
869      } else if (isRegExp(source)) {
870        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
871        destination.lastIndex = source.lastIndex;
872      } else if (isObject(source)) {
873        destination = copy(source, {}, stackSource, stackDest);
874      }
875    }
876  } else {
877    if (source === destination) throw ngMinErr('cpi',
878      "Can't copy! Source and destination are identical.");
879
880    stackSource = stackSource || [];
881    stackDest = stackDest || [];
882
883    if (isObject(source)) {
884      var index = indexOf(stackSource, source);
885      if (index !== -1) return stackDest[index];
886
887      stackSource.push(source);
888      stackDest.push(destination);
889    }
890
891    var result;
892    if (isArray(source)) {
893      destination.length = 0;
894      for ( var i = 0; i < source.length; i++) {
895        result = copy(source[i], null, stackSource, stackDest);
896        if (isObject(source[i])) {
897          stackSource.push(source[i]);
898          stackDest.push(result);
899        }
900        destination.push(result);
901      }
902    } else {
903      var h = destination.$$hashKey;
904      if (isArray(destination)) {
905        destination.length = 0;
906      } else {
907        forEach(destination, function(value, key) {
908          delete destination[key];
909        });
910      }
911      for ( var key in source) {
912        result = copy(source[key], null, stackSource, stackDest);
913        if (isObject(source[key])) {
914          stackSource.push(source[key]);
915          stackDest.push(result);
916        }
917        destination[key] = result;
918      }
919      setHashKey(destination,h);
920    }
921
922  }
923  return destination;
924}
925
926/**
927 * Creates a shallow copy of an object, an array or a primitive
928 */
929function shallowCopy(src, dst) {
930  if (isArray(src)) {
931    dst = dst || [];
932
933    for ( var i = 0; i < src.length; i++) {
934      dst[i] = src[i];
935    }
936  } else if (isObject(src)) {
937    dst = dst || {};
938
939    for (var key in src) {
940      if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
941        dst[key] = src[key];
942      }
943    }
944  }
945
946  return dst || src;
947}
948
949
950/**
951 * @ngdoc function
952 * @name angular.equals
953 * @module ng
954 * @kind function
955 *
956 * @description
957 * Determines if two objects or two values are equivalent. Supports value types, regular
958 * expressions, arrays and objects.
959 *
960 * Two objects or values are considered equivalent if at least one of the following is true:
961 *
962 * * Both objects or values pass `===` comparison.
963 * * Both objects or values are of the same type and all of their properties are equal by
964 *   comparing them with `angular.equals`.
965 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
966 * * Both values represent the same regular expression (In JavaScript,
967 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
968 *   representation matches).
969 *
970 * During a property comparison, properties of `function` type and properties with names
971 * that begin with `$` are ignored.
972 *
973 * Scope and DOMWindow objects are being compared only by identify (`===`).
974 *
975 * @param {*} o1 Object or value to compare.
976 * @param {*} o2 Object or value to compare.
977 * @returns {boolean} True if arguments are equal.
978 */
979function equals(o1, o2) {
980  if (o1 === o2) return true;
981  if (o1 === null || o2 === null) return false;
982  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
983  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
984  if (t1 == t2) {
985    if (t1 == 'object') {
986      if (isArray(o1)) {
987        if (!isArray(o2)) return false;
988        if ((length = o1.length) == o2.length) {
989          for(key=0; key<length; key++) {
990            if (!equals(o1[key], o2[key])) return false;
991          }
992          return true;
993        }
994      } else if (isDate(o1)) {
995        if (!isDate(o2)) return false;
996        return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
997      } else if (isRegExp(o1) && isRegExp(o2)) {
998        return o1.toString() == o2.toString();
999      } else {
1000        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
1001        keySet = {};
1002        for(key in o1) {
1003          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1004          if (!equals(o1[key], o2[key])) return false;
1005          keySet[key] = true;
1006        }
1007        for(key in o2) {
1008          if (!keySet.hasOwnProperty(key) &&
1009              key.charAt(0) !== '$' &&
1010              o2[key] !== undefined &&
1011              !isFunction(o2[key])) return false;
1012        }
1013        return true;
1014      }
1015    }
1016  }
1017  return false;
1018}
1019
1020var csp = function() {
1021  if (isDefined(csp.isActive_)) return csp.isActive_;
1022
1023  var active = !!(document.querySelector('[ng-csp]') ||
1024                  document.querySelector('[data-ng-csp]'));
1025
1026  if (!active) {
1027    try {
1028      /* jshint -W031, -W054 */
1029      new Function('');
1030      /* jshint +W031, +W054 */
1031    } catch (e) {
1032      active = true;
1033    }
1034  }
1035
1036  return (csp.isActive_ = active);
1037};
1038
1039
1040
1041function concat(array1, array2, index) {
1042  return array1.concat(slice.call(array2, index));
1043}
1044
1045function sliceArgs(args, startIndex) {
1046  return slice.call(args, startIndex || 0);
1047}
1048
1049
1050/* jshint -W101 */
1051/**
1052 * @ngdoc function
1053 * @name angular.bind
1054 * @module ng
1055 * @kind function
1056 *
1057 * @description
1058 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1059 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1060 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1061 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1062 *
1063 * @param {Object} self Context which `fn` should be evaluated in.
1064 * @param {function()} fn Function to be bound.
1065 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1066 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1067 */
1068/* jshint +W101 */
1069function bind(self, fn) {
1070  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1071  if (isFunction(fn) && !(fn instanceof RegExp)) {
1072    return curryArgs.length
1073      ? function() {
1074          return arguments.length
1075            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1076            : fn.apply(self, curryArgs);
1077        }
1078      : function() {
1079          return arguments.length
1080            ? fn.apply(self, arguments)
1081            : fn.call(self);
1082        };
1083  } else {
1084    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1085    return fn;
1086  }
1087}
1088
1089
1090function toJsonReplacer(key, value) {
1091  var val = value;
1092
1093  if (typeof key === 'string' && key.charAt(0) === '$') {
1094    val = undefined;
1095  } else if (isWindow(value)) {
1096    val = '$WINDOW';
1097  } else if (value &&  document === value) {
1098    val = '$DOCUMENT';
1099  } else if (isScope(value)) {
1100    val = '$SCOPE';
1101  }
1102
1103  return val;
1104}
1105
1106
1107/**
1108 * @ngdoc function
1109 * @name angular.toJson
1110 * @module ng
1111 * @kind function
1112 *
1113 * @description
1114 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1115 * stripped since angular uses this notation internally.
1116 *
1117 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1118 * @param {boolean=}
1118 pretty If set to true, the JSON output will contain newlines and whitespace.
1119 * @returns {string|undefined} JSON-ified string representing `obj`.
1120 */
1121function toJson(obj, pretty) {
1122  if (typeof obj === 'undefined') return undefined;
1123  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1124}
1125
1126
1127/**
1128 * @ngdoc function
1129 * @name angular.fromJson
1130 * @module ng
1131 * @kind function
1132 *
1133 * @description
1134 * Deserializes a JSON string.
1135 *
1136 * @param {string} json JSON string to deserialize.
1137 * @returns {Object|Array|string|number} Deserialized thingy.
1138 */
1139function fromJson(json) {
1140  return isString(json)
1141      ? JSON.parse(json)
1142      : json;
1143}
1144
1145
1146function toBoolean(value) {
1147  if (typeof value === 'function') {
1148    value = true;
1149  } else if (value && value.length !== 0) {
1150    var v = lowercase("" + value);
1151    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1152  } else {
1153    value = false;
1154  }
1155  return value;
1156}
1157
1158/**
1159 * @returns {string} Returns the string representation of the element.
1160 */
1161function startingTag(element) {
1162  element = jqLite(element).clone();
1163  try {
1164    // turns out IE does not let you set .html() on elements which
1165    // are not allowed to have children. So we just ignore it.
1166    element.empty();
1167  } catch(e) {}
1168  // As Per DOM Standards
1169  var TEXT_NODE = 3;
1170  var elemHtml = jqLite('<div>').append(element).html();
1171  try {
1172    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1173        elemHtml.
1174          match(/^(<[^>]+>)/)[1].
1175          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1176  } catch(e) {
1177    return lowercase(elemHtml);
1178  }
1179
1180}
1181
1182
1183/////////////////////////////////////////////////
1184
1185/**
1186 * Tries to decode the URI component without throwing an exception.
1187 *
1188 * @private
1189 * @param str value potential URI component to check.
1190 * @returns {boolean} True if `value` can be decoded
1191 * with the decodeURIComponent function.
1192 */
1193function tryDecodeURIComponent(value) {
1194  try {
1195    return decodeURIComponent(value);
1196  } catch(e) {
1197    // Ignore any invalid uri component
1198  }
1199}
1200
1201
1202/**
1203 * Parses an escaped url query string into key-value pairs.
1204 * @returns {Object.<string,boolean|Array>}
1205 */
1206function parseKeyValue(/**string*/keyValue) {
1207  var obj = {}, key_value, key;
1208  forEach((keyValue || "").split('&'), function(keyValue) {
1209    if ( keyValue ) {
1210      key_value = keyValue.replace(/\+/g,'%20').split('=');
1211      key = tryDecodeURIComponent(key_value[0]);
1212      if ( isDefined(key) ) {
1213        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1214        if (!hasOwnProperty.call(obj, key)) {
1215          obj[key] = val;
1216        } else if(isArray(obj[key])) {
1217          obj[key].push(val);
1218        } else {
1219          obj[key] = [obj[key],val];
1220        }
1221      }
1222    }
1223  });
1224  return obj;
1225}
1226
1227function toKeyValue(obj) {
1228  var parts = [];
1229  forEach(obj, function(value, key) {
1230    if (isArray(value)) {
1231      forEach(value, function(arrayValue) {
1232        parts.push(encodeUriQuery(key, true) +
1233                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1234      });
1235    } else {
1236    parts.push(encodeUriQuery(key, true) +
1237               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1238    }
1239  });
1240  return parts.length ? parts.join('&') : '';
1241}
1242
1243
1244/**
1245 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1246 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1247 * segments:
1248 *    segment       = *pchar
1249 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1250 *    pct-encoded   = "%" HEXDIG HEXDIG
1251 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1252 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1253 *                     / "*" / "+" / "," / ";" / "="
1254 */
1255function encodeUriSegment(val) {
1256  return encodeUriQuery(val, true).
1257             replace(/%26/gi, '&').
1258             replace(/%3D/gi, '=').
1259             replace(/%2B/gi, '+');
1260}
1261
1262
1263/**
1264 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1265 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1266 * encoded per http://tools.ietf.org/html/rfc3986:
1267 *    query       = *( pchar / "/" / "?" )
1268 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1269 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1270 *    pct-encoded   = "%" HEXDIG HEXDIG
1271 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1272 *                     / "*" / "+" / "," / ";" / "="
1273 */
1274function encodeUriQuery(val, pctEncodeSpaces) {
1275  return encodeURIComponent(val).
1276             replace(/%40/gi, '@').
1277             replace(/%3A/gi, ':').
1278             replace(/%24/g, '$').
1279             replace(/%2C/gi, ',').
1280             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1281}
1282
1283
1284/**
1285 * @ngdoc directive
1286 * @name ngApp
1287 * @module ng
1288 *
1289 * @element ANY
1290 * @param {angular.Module} ngApp an optional application
1291 *   {@link angular.module module} name to load.
1292 *
1293 * @description
1294 *
1295 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1296 * designates the **root element** of the application and is typically placed near the root element
1297 * of the page - e.g. on the `<body>` or `<html>` tags.
1298 *
1299 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
1299p`
1300 * found in the document will be used to define the root element to auto-bootstrap as an
1301 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1302 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1303 *
1304 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1305 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1306 * should contain the application code needed or have dependencies on other modules that will
1307 * contain the code. See {@link angular.module} for more information.
1308 *
1309 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1310 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1311 * would not be resolved to `3`.
1312 *
1313 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1314 *
1315 <example module="ngAppDemo">
1316   <file name="index.html">
1317   <div ng-controller="ngAppDemoController">
1318     I can add: {{a}} + {{b}} =  {{ a+b }}
1319   </div>
1320   </file>
1321   <file name="script.js">
1322   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1323     $scope.a = 1;
1324     $scope.b = 2;
1325   });
1326   </file>
1327 </example>
1328 *
1329 */
1330function angularInit(element, bootstrap) {
1331  var elements = [element],
1332      appElement,
1333      module,
1334      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1335      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1336
1337  function append(element) {
1338    element && elements.push(element);
1339  }
1340
1341  forEach(names, function(name) {
1342    names[name] = true;
1343    append(document.getElementById(name));
1344    name = name.replace(':', '\\:');
1345    if (element.querySelectorAll) {
1346      forEach(element.querySelectorAll('.' + name), append);
1347      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1348      forEach(element.querySelectorAll('[' + name + ']'), append);
1349    }
1350  });
1351
1352  forEach(elements, function(element) {
1353    if (!appElement) {
1354      var className = ' ' + element.className + ' ';
1355      var match = NG_APP_CLASS_REGEXP.exec(className);
1356      if (match) {
1357        appElement = element;
1358        module = (match[2] || '').replace(/\s+/g, ',');
1359      } else {
1360        forEach(element.attributes, function(attr) {
1361          if (!appElement && names[attr.name]) {
1362            appElement = element;
1363            module = attr.value;
1364          }
1365        });
1366      }
1367    }
1368  });
1369  if (appElement) {
1370    bootstrap(appElement, module ? [module] : []);
1371  }
1372}
1373
1374/**
1375 * @ngdoc function
1376 * @name angular.bootstrap
1377 * @module ng
1378 * @description
1379 * Use this function to manually start up angular application.
1380 *
1381 * See: {@link guide/bootstrap Bootstrap}
1382 *
1383 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1384 * They must use {@link ng.directive:ngApp ngApp}.
1385 *
1386 * Angular will detect if it has been loaded into the browser more than once and only allow the
1387 * first loaded script to be bootstrapped and will report a warning to the browser console for
1388 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1389 * multiple instances of Angular try to work on the DOM.
1390 *
1391 * <example name="multi-bootstrap" module="multi-bootstrap">
1392 * <file name="index.html">
1393 * <script src="../../../angular.js"></script>
1394 * <div ng-controller="BrokenTable">
1395 *   <table>
1396 *   <tr>
1397 *     <th ng-repeat="heading in headings">{{heading}}</th>
1398 *   </tr>
1399 *   <tr ng-repeat="filling in fillings">
1400 *     <td ng-repeat="fill in filling">{{fill}}</td>
1401 *   </tr>
1402 * </table>
1403 * </div>
1404 * </file>
1405 * <file name="controller.js">
1406 * var app = angular.module('multi-bootstrap', [])
1407 *
1408 * .controller('BrokenTable', function($scope) {
1409 *     $scope.headings = ['One', 'Two', 'Three'];
1410 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1411 * });
1412 * </file>
1413 * <file name="protractor.js" type="protractor">
1414 * it('should only insert one table cell for each item in $scope.fillings', function() {
1415 *  expect(element.all(by.css('td')).count())
1416 *      .toBe(9);
1417 * });
1418 * </file>
1419 * </example>
1420 *
1421 * @param {DOMElement} element DOM element which is the root of angular application.
1422 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1423 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1424 *     function that will be invoked by the injector as a run block.
1425 *     See: {@link angular.module modules}
1426 * @returns {auto.$injector} Returns the newly created injector for this app.
1427 */
1428function bootstrap(element, modules) {
1429  var doBootstrap = function() {
1430    element = jqLite(element);
1431
1432    if (element.injector()) {
1433      var tag = (element[0] === document) ? 'document' : startingTag(element);
1434      //Encode angle brackets to prevent input from being sanitized to empty string #8683
1435      throw ngMinErr(
1436          'btstrpd',
1437          "App Already Bootstrapped with this Element '{0}'",
1438          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1439    }
1440
1441    modules = modules || [];
1442    modules.unshift(['$provide', function($provide) {
1443      $provide.value('$rootElement', element);
1444    }]);
1445    modules.unshift('ng');
1446    var injector = createInjector(modules);
1447    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1448       function(scope, element, compile, injector, animate) {
1449        scope.$apply(function() {
1450          element.data('$injector', injector);
1451          compile(element)(scope);
1452        });
1453      }]
1454    );
1455    return injector;
1456  };
1457
1458  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1459
1460  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1461    return doBootstrap();
1462  }
1463
1464  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1465  angular.resumeBootstrap = function(extraModules) {
vendor: 2,977 bytes, lines 1466-1567
1466    forEach(extraModules, function(module) {
1467      modules.push(module);
1468    });
1469    doBootstrap();
1470  };
1471}
1472
1473var SNAKE_CASE_REGEXP = /[A-Z]/g;
1474function snake_case(name, separator) {
1475  separator = separator || '_';
1476  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1477    return (pos ? separator : '') + letter.toLowerCase();
1478  });
1479}
1480
1481function bindJQuery() {
1482  // bind to jQuery if present;
1483  jQuery = window.jQuery;
1484  // Use jQuery if it exists with proper functionality, otherwise default to us.
1485  // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support.
1486  if (jQuery && jQuery.fn.on) {
1487    jqLite = jQuery;
1488    extend(jQuery.fn, {
1489      scope: JQLitePrototype.scope,
1490      isolateScope: JQLitePrototype.isolateScope,
1491      controller: JQLitePrototype.controller,
1492      injector: JQLitePrototype.injector,
1493      inheritedData: JQLitePrototype.inheritedData
1494    });
1495    // Method signature:
1496    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1497    jqLitePatchJQueryRemove('remove', true, true, false);
1498    jqLitePatchJQueryRemove('empty', false, false, false);
1499    jqLitePatchJQueryRemove('html', false, false, true);
1500  } else {
1501    jqLite = JQLite;
1502  }
1503  angular.element = jqLite;
1504}
1505
1506/**
1507 * throw error if the argument is falsy.
1508 */
1509function assertArg(arg, name, reason) {
1510  if (!arg) {
1511    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1512  }
1513  return arg;
1514}
1515
1516function assertArgFn(arg, name, acceptArrayAnnotation) {
1517  if (acceptArrayAnnotation && isArray(arg)) {
1518      arg = arg[arg.length - 1];
1519  }
1520
1521  assertArg(isFunction(arg), name, 'not a function, got ' +
1522      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1523  return arg;
1524}
1525
1526/**
1527 * throw error if the name given is hasOwnProperty
1528 * @param  {String} name    the name to test
1529 * @param  {String} context the context in which the name is used, such as module or directive
1530 */
1531function assertNotHasOwnProperty(name, context) {
1532  if (name === 'hasOwnProperty') {
1533    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1534  }
1535}
1536
1537/**
1538 * Return the value accessible from the object by path. Any undefined traversals are ignored
1539 * @param {Object} obj starting object
1540 * @param {String} path path to traverse
1541 * @param {boolean} [bindFnToScope=true]
1542 * @returns {Object} value as accessible by path
1543 */
1544//TODO(misko): this function needs to be removed
1545function getter(obj, path, bindFnToScope) {
1546  if (!path) return obj;
1547  var keys = path.split('.');
1548  var key;
1549  var lastInstance = obj;
1550  var len = keys.length;
1551
1552  for (var i = 0; i < len; i++) {
1553    key = keys[i];
1554    if (obj) {
1555      obj = (lastInstance = obj)[key];
1556    }
1557  }
1558  if (!bindFnToScope && isFunction(obj)) {
1559    return bind(lastInstance, obj);
1560  }
1561  return obj;
1562}
1563
1564/**
1565 * Return the DOM siblings between the first and last node in the given array.
1566 * @param {Array} array like object
1567 * @returns {DOMElement}
1567 object containing the elements
1568 */
1569function getBlockElements(nodes) {
1570  var startNode = nodes[0],
1571      endNode = nodes[nodes.length - 1];
1572  if (startNode === endNode) {
1573    return jqLite(startNode);
1574  }
1575
1576  var element = startNode;
1577  var elements = [element];
1578
1579  do {
1580    element = element.nextSibling;
1581    if (!element) break;
1582    elements.push(element);
1583  } while (element !== endNode);
1584
1585  return jqLite(elements);
1586}
1587
1588/**
1589 * @ngdoc type
1590 * @name angular.Module
1591 * @module ng
1592 * @description
1593 *
1594 * Interface for configuring angular {@link angular.module modules}.
1595 */
1596
1597function setupModuleLoader(window) {
1598
1599  var $injectorMinErr = minErr('$injector');
1600  var ngMinErr = minErr('ng');
1601
1602  function ensure(obj, name, factory) {
1603    return obj[name] || (obj[name] = factory());
1604  }
1605
1606  var angular = ensure(window, 'angular', Object);
1607
1608  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1609  angular.$$minErr = angular.$$minErr || minErr;
1610
1611  return ensure(angular, 'module', function() {
1612    /** @type {Object.<string, angular.Module>} */
1613    var modules = {};
1614
1615    /**
1616     * @ngdoc function
1617     * @name angular.module
1618     * @module ng
1619     * @description
1620     *
1621     * The `angular.module` is a global place for creating, registering and retrieving Angular
1622     * modules.
1623     * All modules (angular core or 3rd party) that should be available to an application must be
1624     * registered using this mechanism.
1625     *
1626     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1627     * existing module (the name passed as the first argument to `module`) is retrieved.
1628     *
1629     *
1630     * # Module
1631     *
1632     * A module is a collection of services, directives, controllers, filters, and configuration information.
1633     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1634     *
1635     * ```js
1636     * // Create a new module
1637     * var myModule = angular.module('myModule', []);
1638     *
1639     * // register a new service
1640     * myModule.value('appName', 'MyCoolApp');
1641     *
1642     * // configure existing services inside initialization blocks.
1643     * myModule.config(['$locationProvider', function($locationProvider) {
1644     *   // Configure existing providers
1645     *   $locationProvider.hashPrefix('!');
1646     * }]);
1647     * ```
1648     *
1649     * Then you can create an injector and load your modules like this:
1650     *
1651     * ```js
1652     * var injector = angular.injector(['ng', 'myModule'])
1653     * ```
1654     *
1655     * However it's more likely that you'll just use
1656     * {@link ng.directive:ngApp ngApp} or
1657     * {@link angular.bootstrap} to simplify this process for you.
1658     *
1659     * @param {!string} name The name of the module to create or retrieve.
1660     * @param {!Array.<string>=} requires If specified then new module is being created. If
1661     *        unspecified then the module is being retrieved for further configuration.
1662     * @param {Function=} configFn Optional configuration function for the module. Same as
1663     *        {@link angular.Module#config Module#config()}.
1664     * @returns {module} new module with the {@link angular.Module} api.
1665     */
1666    return function module(name, requires, configFn) {
1667      var assertNotHasOwnProperty = function(name, context) {
1668        if (name === 'hasOwnProperty') {
1669          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1670        }
1671      };
1672
1673      assertNotHasOwnProperty(name, 'module');
1674      if (requires && modules.hasOwnProperty(name)) {
1675        modules[name] = null;
1676      }
1677      return ensure(modules, name, function() {
1678        if (!requires) {
1679          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1680             "the module name or forgot to load it. If registering a module ensure that you " +
1681             "specify the dependencies as the second argument.", name);
1682        }
1683
1684        /** @type {!Array.<Array.<*>>} */
1685        var invokeQueue = [];
1686
1687        /** @type {!Array.<Function>} */
1688        var runBlocks = [];
1689
1690        var config = invokeLater('$injector', 'invoke');
1691
1692        /** @type {angular.Module} */
1693        var moduleInstance = {
1694          // Private state
1695          _invokeQueue: invokeQueue,
1696          _runBlocks: runBlocks,
1697
1698          /**
1699           * @ngdoc property
1700           * @name angular.Module#requires
1701           * @module ng
1702           *
1703           * @description
1704           * Holds the list of modules which the injector will load before the current module is
1705           * loaded.
1706           */
1707          requires: requires,
1708
1709          /**
1710           * @ngdoc property
1711           * @name angular.Module#name
1712           * @module ng
1713           *
1714           * @description
1715           * Name of the module.
1716           */
1717          name: name,
1718
1719
1720          /**
1721           * @ngdoc method
1722           * @name angular.Module#provider
1723           * @module ng
1724           * @param {string} name service name
1725           * @param {Function} providerType Construction function for creating new instance of the
1726           *                                service.
1727           * @description
1728           * See {@link auto.$provide#provider $provide.provider()}.
1729           */
1730          provider: invokeLater('$provide', 'provider'),
1731
1732          /**
1733           * @ngdoc method
1734           * @name angular.Module#factory
1735           * @module ng
1736           * @param {string} name service name
1737           * @param {Function} providerFunction Function for creating new instance of the service.
1738           * @description
1739           * See {@link auto.$provide#factory $provide.factory()}.
1740           */
1741          factory: invokeLater('$provide', 'factory'),
1742
1743          /**
1744           * @ngdoc method
1745           * @name angular.Module#service
1746           * @module ng
1747           * @param {string} name service name
1748           * @param {Function} constructor A constructor function that will be instantiated.
1749           * @description
1750           * See {@link auto.$provide#service $provide.service()}.
1751           */
1752          service: invokeLater('$provide', 'service'),
1753
1754          /**
1755           * @ngdoc method
1756           * @name angular.Module#value
1757           * @module ng
1758           * @param {string} name service name
1759           * @param {*} object Service instance object.
1760           * @description
1761           * See {@link auto.$provide#value $provide.value()}.
1762           */
1763          value: invokeLater('$provide', 'value'),
1764
1765          /**
1766           * @ngdoc method
1767           * @name angular.Module#constant
1768           * @module ng
1769           * @param {string} name constant name
1770           * @param {*} object Constant value.
1771           * @description
1772           * Because the constant are fixed, they get applied before other provide methods.
1773           * See {@link auto.$provide#constant $provide.constant()}.
1774           */
1775          constant: invokeLater('$provide', 'constant', 'unshift'),
1776
1777          /**
1778           * @ngdoc method
1779           * @name angular.Module#animation
1780           * @module ng
1781           * @param {string} name animation name
1782           * @param {Function} animationFactory Factory function for creating new instance of an
1783           *                                    animation.
1784           * @description
1785           *
1786           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1787           *
1788           *
1789           * Defines an animation hook that can be later used with
1790           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1791           *
1792           * ```js
1793           * module.animation('.animation-name', function($inject1, $inject2) {
1794           *   return {
1795           *     eventName : function(element, done) {
1796           *       //code to run the animation
1797           *       //once complete, then run done()
1798           *       return function cancellationFunction(element) {
1799           *         //code to cancel the animation
1800           *       }
1801           *     }
1802           *   }
1803           * })
1804           * ```
1805           *
1806           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1807           * {@link ngAnimate ngAnimate module} for more information.
1808           */
1809          animation: invokeLater('$animateProvider', 'register'),
1810
1811          /**
1812           * @ngdoc method
1813           * @name angular.Module#filter
1814           * @module ng
1815           * @param {string} name Filter name.
1816           * @param {Function} filterFactory Factory function for creating new instance of filter.
1817           * @description
1818           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1819           */
1820          filter: invokeLater('$filterProvider', 'register'),
1821
1822          /**
1823           * @ngdoc method
1824           * @name angular.Module#controller
1825           * @module ng
1826           * @param {string|Object} name Controller name, or an object map of controllers where the
1827           *    keys are the names and the values are the constructors.
1828           * @param {Function} constructor Controller constructor function.
1829           * @description
1830           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1831           */
1832          controller: invokeLater('$controllerProvider', 'register'),
1833
1834          /**
1835           * @ngdoc method
1836           * @name angular.Module#directive
1837           * @module ng
1838           * @param {string|Object} name Directive name, or an object map of directives where the
1839           *    keys are the names and the values are the factories.
1840           * @param {Function} directiveFactory Factory function for creating new instance of
1841           * directives.
1842           * @description
1843           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1844           */
1845          directive: invokeLater('$compileProvider', 'directive'),
1846
1847          /**
1848           * @ngdoc method
1849           * @name angular.Module#config
1850           * @module ng
1851           * @param {Function} configFn Execute this function on module load. Useful for service
1852           *    configuration.
1853           * @description
1854           * Use this method to register work which needs to be performed on module loading.
1855           * For more about how to configure services, see
1856           * {@link providers#providers_provider-recipe Provider Recipe}.
1857           */
1858          config: config,
1859
1860          /**
1861           * @ngdoc method
1862           * @name angular.Module#run
1863           * @module ng
1864           * @param {Function} initializationFn Execute this function after injector creation.
1865           *    Useful for application initialization.
1866           * @description
1867           * Use this method to register work which should be performed when the injector is done
1868           * loading all modules.
1869           */
1870          run: function(block) {
1871            runBlocks.push(block);
1872            return this;
1873          }
1874        };
1875
1876        if (configFn) {
1877          config(configFn);
1878        }
1879
1880        return  moduleInstance;
1881
1882        /**
1883         * @param {string} provider
1884         * @param {string} method
1885         * @param {String=} insertMethod
1886         * @returns {angular.Module}
1887         */
1888        function invokeLater(provider, method, insertMethod) {
1889          return function() {
1890            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1891            return moduleInstance;
1892          };
1893        }
1894      });
1895    };
1896  });
1897
1898}
1899
1900/* global angularModule: true,
1901  version: true,
1902
1903  $LocaleProvider,
1904  $CompileProvider,
1905
1906    htmlAnchorDirective,
1907    inputDirective,
1908    inputDirective,
1909    formDirective,
1910    scriptDirective,
1911    selectDirective,
1912    styleDirective,
1913    optionDirective,
1914    ngBindDirective,
1915    ngBindHtmlDirective,
1916    ngBindTemplateDirective,
1917    ngClassDirective,
1918    ngClassEvenDirective,
1919    ngClassOddDirective,
1920    ngCspDirective,
1921    ngCloakDirective,
1922    ngControllerDirective,
1923    ngFormDirective,
1924    ngHideDirective,
1925    ngIfDirective,
1926    ngIncludeDirective,
1927    ngIncludeFillContentDirective,
1928    ngInitDirective,
1929    ngNonBindableDirective,
1930    ngPluralizeDirective,
1931    ngRepeatDirective,
1932    ngShowDirective,
1933    ngStyleDirective,
1934    ngSwitchDirective,
1935    ngSwitchWhenDirective,
1936    ngSwitchDefaultDirective,
1937    ngOptionsDirective,
1938    ngTranscludeDirective,
1939    ngModelDirective,
1940    ngListDirective,
1941    ngChangeDirective,
1942    requiredDirective,
1943    requiredDirective,
1944    ngValueDirective,
1945    ngAttributeAliasDirectives,
1946    ngEventDirectives,
1947
1948    $AnchorScrollProvider,
1949    $AnimateProvider,
1950    $BrowserProvider,
1951    $CacheFactoryProvider,
1952    $ControllerProvider,
1953    $DocumentProvider,
1954    $ExceptionHandlerProvider,
1955    $FilterProvider,
1956    $InterpolateProvider,
1957    $IntervalProvider,
1958    $HttpProvider,
1959    $HttpBackendProvider,
1960    $LocationProvider,
1961    $LogProvider,
1962    $ParseProvider,
1963    $RootScopeProvider,
1964    $QProvider,
1965    $$SanitizeUriProvider,
1966    $SceProvider,
1967    $SceDelegateProvider,
1968    $SnifferProvider,
1969    $TemplateCacheProvider,
1970    $TimeoutProvider,
1971    $$RAFProvider,
1972    $$AsyncCallbackProvider,
1973    $WindowProvider
1974*/
1975
1976
1977/**
1978 * @ngdoc object
1979 * @name angular.version
1980 * @module ng
1981 * @description
1982 * An object that contains information about the current AngularJS version. This object has the
1983 * following properties:
1984 *
1985 * - `full` – `{string}` – Full version string, such as "0.9.18".
1986 * - `major` – `{number}` – Major version number, such as "0".
1987 * - `minor` – `{number}` – Minor version number, such as "9".
1988 * - `dot` – `{number}` – Dot version number, such as "18".
1989 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1990 */
1991var version = {
1992  full: '1.2.32',    // all of these placeholder strings will be replaced by grunt's
1993  major: 1,    // package task
1994  minor: 2,
1995  dot: 32,
1996  codeName: 'alternation-intention'
1997};
1998
1999
2000function publishExternalAPI(angular){
2001  extend(angular, {
2002    'bootstrap': bootstrap,
2003    'copy': copy,
2004    'extend': extend,
2005    'equals': equals,
2006    'element': jqLite,
2007    'forEach': forEach,
2008    'injector': createInjector,
2009    'noop': noop,
2010    'bind': bind,
2011    'toJson': toJson,
2012    'fromJson': fromJson,
2013    'identity': identity,
2014    'isUndefined': isUndefined,
2015    'isDefined': isDefined,
2016    'isString': isString,
2017    'isFunction': isFunction,
2018    'isObject': isObject,
2019    'isNumber': isNumber,
2020    'isElement': isElement,
2021    'isArray': isArray,
2022    'version': version,
2023    'isDate': isDate,
2024    'lowercase': lowercase,
2025    'uppercase': uppercase,
2026    'callbacks': {counter: 0},
2027    '$$minErr': minErr,
2028    '$$csp': csp
2029  });
2030
2031  angularModule = setupModuleLoader(window);
2032  try {
2033    angularModule('ngLocale');
2034  } catch (e) {
2035    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2036  }
2037
2038  angularModule('ng', ['ngLocale'], ['$provide',
2039    function ngModule($provide) {
2040      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2041      $provide.provider({
2042        $$sanitizeUri: $$SanitizeUriProvider
2043      });
2044      $provide.provider('$compile', $CompileProvider).
2045        directive({
2046            a: htmlAnchorDirective,
2047            input: inputDirective,
2048            textarea: inputDirective,
2049            form: formDirective,
2050            script: scriptDirective,
2051            select: selectDirective,
2052            style: styleDirective,
2053            option: optionDirective,
2054            ngBind: ngBindDirective,
2055            ngBindHtml: ngBindHtmlDirective,
2056            ngBindTemplate: ngBindTemplateDirective,
2057            ngClass: ngClassDirective,
2058            ngClassEven: ngClassEvenDirective,
2059            ngClassOdd: ngClassOddDirective,
2060            ngCloak: ngCloakDirective,
2061            ngController: ngControllerDirective,
2062            ngForm: ngFormDirective,
2063            ngHide: ngHideDirective,
2064            ngIf: ngIfDirective,
2065            ngInclude: ngIncludeDirective,
2066            ngInit: ngInitDirective,
2067            ngNonBindable: ngNonBindableDirective,
2068            ngPluralize: ngPluralizeDirective,
2069            ngRepeat: ngRepeatDirective,
2070            ngShow: ngShowDirective,
2071            ngStyle: ngStyleDirective,
2072            ngSwitch: ngSwitchDirective,
2073            ngSwitchWhen: ngSwitchWhenDirective,
2074            ngSwitchDefault: ngSwitchDefaultDirective,
2075            ngOptions: ngOptionsDirective,
2076            ngTransclude: ngTranscludeDirective,
2077            ngModel: ngModelDirective,
2078            ngList: ngListDirective,
2079            ngChange: ngChangeDirective,
2080            required: requiredDirective,
2081            ngRequired: requiredDirective,
2082            ngValue: ngValueDirective
2083        }).
2084        directive({
2085          ngInclude: ngIncludeFillContentDirective
2086        }).
2087        directive(ngAttributeAliasDirectives).
2088        directive(ngEventDirectives);
2089      $provide.provider({
2090        $anchorScroll: $AnchorScrollProvider,
2091        $animate: $AnimateProvider,
2092        $browser: $BrowserProvider,
2093        $cacheFactory: $CacheFactoryProvider,
2094        $controller: $ControllerProvider,
2095        $document: $DocumentProvider,
2096        $exceptionHandler: $ExceptionHandlerProvider,
2097        $filter: $FilterProvider,
2098        $interpolate: $InterpolateProvider,
2099        $interval: $IntervalProvider,
2100        $http: $HttpProvider,
2101        $httpBackend: $HttpBackendProvider,
2102        $location: $LocationProvider,
2103        $log: $LogProvider,
2104        $parse: $ParseProvider,
2105        $rootScope: $RootScopeProvider,
2106        $q: $QProvider,
2107        $sce: $SceProvider,
2108        $sceDelegate: $SceDelegateProvider,
2109        $sniffer: $SnifferProvider,
2110        $templateCache: $TemplateCacheProvider,
2111        $timeout: $TimeoutProvider,
2112        $window: $WindowProvider,
2113        $$rAF: $$RAFProvider,
2114        $$asyncCallback : $$AsyncCallbackProvider
2115      });
2116    }
2117  ]);
2118}
2119
2120/* global JQLitePrototype: true,
2121  addEventListenerFn: true,
2122  removeEventListenerFn: true,
2123  BOOLEAN_ATTR: true
2124*/
2125
2126//////////////////////////////////
2127//JQLite
2128//////////////////////////////////
2129
2130/**
2131 * @ngdoc function
2132 * @name angular.element
2133 * @module ng
2134 * @kind function
2135 *
2136 * @description
2137 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2138 *
2139 * If jQuery is available, `angular.element` is an alias for the
2140 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2141 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2142 *
2143 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2144 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2145 * commonly needed functionality with the goal of having a very small footprint.</div>
2146 *
2147 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2148 *
2149 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2150 * jqLite; they are never raw DOM references.</div>
2151 *
2152 * ## Angular's jqLite
2153 * jqLite provides only the following jQuery methods:
2154 *
2155 * - [`addClass()`](http://api.jquery.com/addClass/)
2156 * - [`after()`](http://api.jquery.com/after/)
2157 * - [`append()`](http://api.jquery.com/append/)
2158 * - [`attr()`](http://api.jquery.com/attr/)
2159 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2160 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2161 * - [`clone()`](http://api.jquery.com/clone/)
2162 * - [`contents()`](http://api.jquery.com/contents/)
2163 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
2164 * - [`data()`](http://api.jquery.com/data/)
2165 * - [`empty()`](http://api.jquery.com/empty/)
2166 * - [`eq()`](http://api.jquery.com/eq/)
2167 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2168 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2169 * - [`html()`](http://api.jquery.com/html/)
2170 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2171 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2172 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2173 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2174 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2175 * - [`prepend()`](http://api.jquery.com/prepend/)
2176 * - [`prop()`](http://api.jquery.com/prop/)
2177 * - [`ready()`](http://api.jquery.com/ready/)
2178 * - [`remove()`](http://api.jquery.com/remove/)
2179 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2180 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2181 * - [`removeData()`](http://api.jquery.com/removeData/)
2182 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2183 * - [`text()`](http://api.jquery.com/text/)
2184 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2185 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2186 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2187 * - [`val()`](http://api.jquery.com/val/)
2188 * - [`wrap()`](http://api.jquery.com/wrap/)
2189 *
2190 * ## jQuery/jqLite Extras
2191 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2192 *
2193 * ### Events
2194 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2194pis and fires this event
2195 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2196 *    element before it is removed.
2197 *
2198 * ### Methods
2199 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2200 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2201 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2202 *   `'ngModel'`).
2203 * - `injector()` - retrieves the injector of the current element or its parent.
2204 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2205 *   element or its parent.
2206 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2207 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2208 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2209 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2210 *   parent element is reached.
2211 *
2212 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2213 * @returns {Object} jQuery object.
2214 */
2215
2216JQLite.expando = 'ng339';
2217
2218var jqCache = JQLite.cache = {},
2219    jqId = 1,
2220    addEventListenerFn = (window.document.addEventListener
2221      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2222      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2223    removeEventListenerFn = (window.document.removeEventListener
2224      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2225      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2226
2227/*
2228 * !!! This is an undocumented "private" function !!!
2229 */
2230var jqData = JQLite._data = function(node) {
2231  //jQuery always returns an object on cache miss
2232  return this.cache[node[this.expando]] || {};
2233};
2234
2235function jqNextId() { return ++jqId; }
2236
2237
2238var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2239var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2240var jqLiteMinErr = minErr('jqLite');
2241
2242/**
2243 * Converts snake_case to camelCase.
2244 * Also there is special case for Moz prefix starting with upper case letter.
2245 * @param name Name to normalize
2246 */
2247function camelCase(name) {
2248  return name.
2249    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2250      return offset ? letter.toUpperCase() : letter;
2251    }).
2252    replace(MOZ_HACK_REGEXP, 'Moz$1');
2253}
2254
2255/////////////////////////////////////////////
2256// jQuery mutation patch
2257//
2258// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2259// $destroy event on all DOM nodes being removed.
2260//
2261/////////////////////////////////////////////
2262
2263function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2264  var originalJqFn = jQuery.fn[name];
2265  originalJqFn = originalJqFn.$original || originalJqFn;
2266  removePatch.$original = originalJqFn;
2267  jQuery.fn[name] = removePatch;
2268
2269  function removePatch(param) {
2270    // jshint -W040
2271    var list = filterElems && param ? [this.filter(param)] : [this],
2272        fireEvent = dispatchThis,
2273        set, setIndex, setLength,
2274        element, childIndex, childLength, children;
2275
2276    if (!getterIfNoArguments || param != null) {
2277      while(list.length) {
2278        set = list.shift();
2279        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2280          element = jqLite(set[setIndex]);
2281          if (fireEvent) {
2282            element.triggerHandler('$destroy');
2283          } else {
2284            fireEvent = !fireEvent;
2285          }
2286          for(childIndex = 0, childLength = (children = element.children()).length;
2287              childIndex < childLength;
2288              childIndex++) {
2289            list.push(jQuery(children[childIndex]));
2290          }
2291        }
2292      }
2293    }
2294    return originalJqFn.apply(this, arguments);
2295  }
2296}
2297
2298var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2299var HTML_REGEXP = /<|&#?\w+;/;
2300var TAG_NAME_REGEXP = /<([\w:]+)/;
2301var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2302
2303var wrapMap = {
2304  'option': [1, '<select multiple="multiple">', '</select>'],
2305
2306  'thead': [1, '<table>', '</table>'],
2307  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2308  'tr': [2, '<table><tbody>', '</tbody></table>'],
2309  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2310  '_default': [0, "", ""]
2311};
2312
2313wrapMap.optgroup = wrapMap.option;
2314wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2315wrapMap.th = wrapMap.td;
2316
2317function jqLiteIsTextNode(html) {
2318  return !HTML_REGEXP.test(html);
2319}
2320
2321function jqLiteBuildFragment(html, context) {
2322  var elem, tmp, tag, wrap,
2323      fragment = context.createDocumentFragment(),
2324      nodes = [], i, j, jj;
2325
2326  if (jqLiteIsTextNode(html)) {
2327    // Convert non-html into a text node
2328    nodes.push(context.createTextNode(html));
2329  } else {
2330    tmp = fragment.appendChild(context.createElement('div'));
2331    // Convert html into DOM nodes
2332    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2333    wrap = wrapMap[tag] || wrapMap._default;
2334    tmp.innerHTML = '<div>&#160;</div>' +
2335      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2336    tmp.removeChild(tmp.firstChild);
2337
2338    // Descend through wrappers to the right content
2339    i = wrap[0];
2340    while (i--) {
2341      tmp = tmp.lastChild;
2342    }
2343
2344    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
2345
2346    tmp = fragment.firstChild;
2347    tmp.textContent = "";
2348  }
2349
2350  // Remove wrapper from fragment
2351  fragment.textContent = "";
2352  fragment.innerHTML = ""; // Clear inner HTML
2353  return nodes;
2354}
2355
2356function jqLiteParseHTML(html, context) {
2357  context = context || document;
2358  var parsed;
2359
2360  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2361    return [context.createElement(parsed[1])];
2362  }
2363
2364  return jqLiteBuildFragment(html, context);
2365}
2366
2367/////////////////////////////////////////////
2368function JQLite(element) {
2369  if (element instanceof JQLite) {
2370    return element;
2371  }
2372  if (isString(element)) {
2373    element = trim(element);
2374  }
2375  if (!(this instanceof JQLite)) {
2376    if (isString(element) && element.charAt(0) != '<') {
2377      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2378    }
2379    return new JQLite(element);
2380  }
2381
2382  if (isString(element)) {
2383    jqLiteAddNodes(this, jqLiteParseHTML(element));
2384    var fragment = jqLite(document.createDocumentFragment());
2385    fragment.append(this);
2386  } else {
2387    jqLiteAddNodes(this, element);
2388  }
2389}
2390
2391function jqLiteClone(element) {
2392  return element.cloneNode(true);
2393}
2394
2395function jqLiteDealoc(element){
2396  jqLiteRemoveData(element);
2397  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2398    jqLiteDealoc(children[i]);
2399  }
2400}
2401
2402function jqLiteOff(element, type, fn, unsupported) {
2403  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2404
2405  var events = jqLiteExpandoStore(element, 'events'),
2406      handle = jqLiteExpandoStore(element, 'handle');
2407
2408  if (!handle) return; //no listeners registered
2409
2410  if (isUndefined(type)) {
2411    forEach(events, function(eventHandler, type) {
2412      removeEventListenerFn(element, type, eventHandler);
2413      delete events[type];
2414    });
2415  } else {
2416    forEach(type.split(' '), function(type) {
2417      if (isUndefined(fn)) {
2418        removeEventListenerFn(element, type, events[type]);
2419        delete events[type];
2420      } else {
2421        arrayRemove(events[type] || [], fn);
2422      }
2423    });
2424  }
2425}
2426
2427function jqLiteRemoveData(element, name) {
2428  var expandoId = element.ng339,
2429      expandoStore = jqCache[expandoId];
2430
2431  if (expandoStore) {
2432    if (name) {
2433      delete jqCache[expandoId].data[name];
2434      return;
2435    }
2436
2437    if (expandoStore.handle) {
2438      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2439      jqLiteOff(element);
2440    }
2441    delete jqCache[expandoId];
2442    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2443  }
2444}
2445
2446function jqLiteExpandoStore(element, key, value) {
2447  var expandoId = element.ng339,
2448      expandoStore = jqCache[expandoId || -1];
2449
2450  if (isDefined(value)) {
2451    if (!expandoStore) {
2452      element.ng339 = expandoId = jqNextId();
2453      expandoStore = jqCache[expandoId] = {};
2454    }
2455    expandoStore[key] = value;
2456  } else {
2457    return expandoStore && expandoStore[key];
2458  }
2459}
2460
2461function jqLiteData(element, key, value) {
2462  var data = jqLiteExpandoStore(element, 'data'),
2463      isSetter = isDefined(value),
2464      keyDefined = !isSetter && isDefined(key),
2465      isSimpleGetter = keyDefined && !isObject(key);
2466
2467  if (!data && !isSimpleGetter) {
2468    jqLiteExpandoStore(element, 'data', data = {});
2469  }
2470
2471  if (isSetter) {
2472    data[key] = value;
2473  } else {
2474    if (keyDefined) {
2475      if (isSimpleGetter) {
2476        // don't create data in this case.
2477        return data && data[key];
2478      } else {
2479        extend(data, key);
2480      }
2481    } else {
2482      return data;
2483    }
2484  }
2485}
2486
2487function jqLiteHasClass(element, selector) {
2488  if (!element.getAttribute) return false;
2489  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2490      indexOf( " " + selector + " " ) > -1);
2491}
2492
2493function jqLiteRemoveClass(element, cssClasses) {
2494  if (cssClasses && element.setAttribute) {
2495    forEach(cssClasses.split(' '), function(cssClass) {
2496      element.setAttribute('class', trim(
2497          (" " + (element.getAttribute('class') || '') + " ")
2498          .replace(/[\n\t]/g, " ")
2499          .replace(" " + trim(cssClass) + " ", " "))
2500      );
2501    });
2502  }
2503}
2504
2505function jqLiteAddClass(element, cssClasses) {
2506  if (cssClasses && element.setAttribute) {
2507    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2508                            .replace(/[\n\t]/g, " ");
2509
2510    forEach(cssClasses.split(' '), function(cssClass) {
2511      cssClass = trim(cssClass);
2512      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2513        existingClasses += cssClass + ' ';
2514      }
2515    });
2516
2517    element.setAttribute('class', trim(existingClasses));
2518  }
2519}
2520
2521function jqLiteAddNodes(root, elements) {
2522  if (elements) {
2523    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2524      ? elements
2525      : [ elements ];
2526    for(var i=0; i < elements.length; i++) {
2527      root.push(elements[i]);
2528    }
2529  }
2530}
2531
2532function jqLiteController(element, name) {
2533  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2534}
2535
2536function jqLiteInheritedData(element, name, value) {
2537  // if element is the document object work with the html element instead
2538  // this makes $(document).scope() possible
2539  if(element.nodeType == 9) {
2540    element = element.documentElement;
2541  }
2542  var names = isArray(name) ? name : [name];
2543
2544  while (element) {
2545    for (var i = 0, ii = names.length; i < ii; i++) {
2546      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2547    }
2548
2549    // If dealing with a document fragment node with a host element, and no parent, use the host
2550    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2551    // to lookup parent controllers.
2552    element = element.parentNode || (element.nodeType === 11 && element.host);
2553  }
2554}
2555
2556function jqLiteEmpty(element) {
2557  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2558    jqLiteDealoc(childNodes[i]);
2559  }
2560  while (element.firstChild) {
2561    element.removeChild(element.firstChild);
2562  }
2563}
2564
2565//////////////////////////////////////////
2566// Functions which are declared directly.
2567//////////////////////////////////////////
2568var JQLitePrototype = JQLite.prototype = {
2569  ready: function(fn) {
2570    var fired = false;
2571
2572    function trigger() {
2573      if (fired) return;
2574      fired = true;
2575      fn();
2576    }
2577
2578    // check if document already is loaded
2579    if (document.readyState === 'complete'){
2580      setTimeout(trigger);
2581    } else {
2582      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2583      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2584      // jshint -W064
2585      JQLite(window).on('load', trigger); // fallback to window.onload for others
2586      // jshint +W064
2587    }
2588  },
2589  toString: function() {
2590    var value = [];
2591    forEach(this, function(e){ value.push('' + e);});
2592    return '[' + value.join(', ') + ']';
2593  },
2594
2595  eq: function(index) {
2596      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2597  },
2598
2599  length: 0,
2600  push: push,
2601  sort: [].sort,
2602  splice: [].splice
2603};
2604
2605//////////////////////////////////////////
2606// Functions iterating getter/setters.
2607// these functions return self on setter and
2608// value on get.
2609//////////////////////////////////////////
2610var BOOLEAN_ATTR = {};
2611forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2612  BOOLEAN_ATTR[lowercase(value)] = value;
2613});
2614var BOOLEAN_ELEMENTS = {};
2615forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2616  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2617});
2618
2619function getBooleanAttrName(element, name) {
2620  // check dom last since we will most likely fail on name
2621  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2622
2623  // booleanAttr is here twice to minimize DOM access
2624  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2625}
2626
2627forEach({
2628  data: jqLiteData,
2629  removeData: jqLiteRemoveData
2630}, function(fn, name) {
2631  JQLite[name] = fn;
2632});
2633
2634forEach({
2635  data: jqLiteData,
2636  inheritedData: jqLiteInheritedData,
2637
2638  scope: function(element) {
2639    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2640    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2641  },
2642
2643  isolateScope: function(element) {
2644    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2645    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2646  },
2647
2648  controller: jqLiteController,
2649
2650  injector: function(element) {
2651    return jqLiteInheritedData(element, '$injector');
2652  },
2653
2654  removeAttr: function(element,name) {
2655    element.removeAttribute(name);
2656  },
2657
2658  hasClass: jqLiteHasClass,
2659
2660  css: function(element, name, value) {
2661    name = camelCase(name);
2662
2663    if (isDefined(value)) {
2664      element.style[name] = value;
2665    } else {
2666      var val;
2667
2668      if (msie <= 8) {
2669        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2670        val = element.currentStyle && element.currentStyle[name];
2671        if (val === '') val = 'auto';
2672      }
2673
2674      val = val || element.style[name];
2675
2676      if (msie <= 8) {
2677        // jquery weirdness :-/
2678        val = (val === '') ? undefined : val;
2679      }
2680
2681      return  val;
2682    }
2683  },
2684
2685  attr: function(element, name, value){
2686    var lowercasedName = lowercase(name);
2687    if (BOOLEAN_ATTR[lowercasedName]) {
2688      if (isDefined(value)) {
2689        if (!!value) {
2690          element[name] = true;
2691          element.setAttribute(name, lowercasedName);
2692        } else {
2693          element[name] = false;
2694          element.removeAttribute(lowercasedName);
2695        }
2696      } else {
2697        return (element[name] ||
2698                 (element.attributes.getNamedItem(name)|| noop).specified)
2699               ? lowercasedName
2700               : undefined;
2701      }
2702    } else if (isDefined(value)) {
2703      element.setAttribute(name, value);
2704    } else if (element.getAttribute) {
2705      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2706      // some elements (e.g. Document) don't have get attribute, so return undefined
2707      var ret = element.getAttribute(name, 2);
2708      // normalize non-existing attributes to undefined (as jQuery)
2709      return ret === null ? undefined : ret;
2710    }
2711  },
2712
2713  prop: function(element, name, value) {
2714    if (isDefined(value)) {
2715      element[name] = value;
2716    } else {
2717      return element[name];
2718    }
2719  },
2720
2721  text: (function() {
2722    var NODE_TYPE_TEXT_PROPERTY = [];
2723    if (msie < 9) {
2724      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2725      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2726    } else {
2727      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2728      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2729    }
2730    getText.$dv = '';
2731    return getText;
2732
2733    function getText(element, value) {
2734      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2735      if (isUndefined(value)) {
2736        return textProp ? element[textProp] : '';
2737      }
2738      element[textProp] = value;
2739    }
2740  })(),
2741
2742  val: function(element, value) {
2743    if (isUndefined(value)) {
2744      if (nodeName_(element) === 'SELECT' && element.multiple) {
2745        var result = [];
2746        forEach(element.options, function (option) {
2747          if (option.selected) {
2748            result.push(option.value || option.text);
2749          }
2750        });
2751        return result.length === 0 ? null : result;
2752      }
2753      return element.value;
2754    }
2755    element.value = value;
2756  },
2757
2758  html: function(element, value) {
2759    if (isUndefined(value)) {
2760      return element.innerHTML;
2761    }
2762    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2763      jqLiteDealoc(childNodes[i]);
2764    }
2765    element.innerHTML = value;
2766  },
2767
2768  empty: jqLiteEmpty
2769}, function(fn, name){
2770  /**
2771   * Properties: writes return selection, reads return first value
2772   */
2773  JQLite.prototype[name] = function(arg1, arg2) {
2774    var i, key;
2775    var nodeCount = this.length;
2776
2777    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2778    // in a way that survives minification.
2779    // jqLiteEmpty takes no arguments but is a setter.
2780    if (fn !== jqLiteEmpty &&
2781        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2782      if (isObject(arg1)) {
2783
2784        // we are a write, but the object properties are the key/values
2785        for (i = 0; i < nodeCount; i++) {
2786          if (fn === jqLiteData) {
2787            // data() takes the whole object in jQuery
2788            fn(this[i], arg1);
2789          } else {
2790            for (key in arg1) {
2791              fn(this[i], key, arg1[key]);
2792            }
2793          }
2794        }
2795        // return self for chaining
2796        return this;
2797      } else {
2798        // we are a read, so read the first child.
2799        // TODO: do we still need this?
2800        var value = fn.$dv;
2801        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2802        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2803        for (var j = 0; j < jj; j++) {
2804          var nodeValue = fn(this[j], arg1, arg2);
2805          value = value ? value + nodeValue : nodeValue;
2806        }
2807        return value;
2808      }
2809    } else {
2810      // we are a write, so apply to all children
2811      for (i = 0; i < nodeCount; i++) {
2812        fn(this[i], arg1, arg2);
2813      }
2814      // return self for chaining
2815      return this;
2816    }
2817  };
2818});
2819
2820function createEventHandler(element, events) {
2821  var eventHandler = function (event, type) {
2822    if (!event.preventDefault) {
2823      event.preventDefault = function() {
2824        event.returnValue = false; //ie
2825      };
2826    }
2827
2828    if (!event.stopPropagation) {
2829      event.stopPropagation = function() {
2830        event.cancelBubble = true; //ie
2831      };
2832    }
2833
2834    if (!event.target) {
2835      event.target = event.srcElement || document;
2836    }
2837
2838    if (isUndefined(event.defaultPrevented)) {
2839      var prevent = event.preventDefault;
2840      event.preventDefault = function() {
2841        event.defaultPrevented = true;
2842        prevent.call(event);
2843      };
2844      event.defaultPrevented = false;
2845    }
2846
2847    event.isDefaultPrevented = function() {
2848      return event.defaultPrevented || event.returnValue === false;
2849    };
2850
2851    // Copy event handlers in case event handlers array is modified during execution.
2852    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2853
2854    forEach(eventHandlersCopy, function(fn) {
2855      fn.call(element, event);
2856    });
2857
2858    // Remove monkey-patched methods (IE),
2859    // as they would cause memory leaks in IE8.
2860    if (msie <= 8) {
2861      // IE7/8 does not allow to delete property on native object
2862      event.preventDefault = null;
2863      event.stopPropagation = null;
2864      event.isDefaultPrevented = null;
2865    } else {
2866      // It shouldn't affect normal browsers (native methods are defined on prototype).
2867      delete event.preventDefault;
2868      delete event.stopPropagation;
2869      delete event.isDefaultPrevented;
2870    }
2871  };
2872  eventHandler.elem = element;
2873  return eventHandler;
2874}
2875
2876//////////////////////////////////////////
2877// Functions iterating traversal.
2878// These functions chain results into a single
2879// selector.
2880//////////////////////////////////////////
2881forEach({
2882  removeData: jqLiteRemoveData,
2883
2884  dealoc: jqLiteDealoc,
2885
2886  on: function onFn(element, type, fn, unsupported){
2887    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2888
2889    var events = jqLiteExpandoStore(element, 'events'),
2890        handle = jqLiteExpandoStore(element, 'handle');
2891
2892    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2893    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2894
2895    forEach(type.split(' '), function(type){
2896      var eventFns = events[type];
2897
2898      if (!eventFns) {
2899        if (type == 'mouseenter' || type == 'mouseleave') {
2900          var contains = document.body.contains || document.body.compareDocumentPosition ?
2901          function( a, b ) {
2902            // jshint bitwise: false
2903            var adown = a.nodeType === 9 ? a.documentElement : a,
2904            bup = b && b.parentNode;
2905            return a === bup || !!( bup && bup.nodeType === 1 && (
2906              adown.contains ?
2907              adown.contains( bup ) :
2908              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2909              ));
2910            } :
2911            function( a, b ) {
2912              if ( b ) {
2913                while ( (b = b.parentNode) ) {
2914                  if ( b === a ) {
2915                    return true;
2916                  }
2917                }
2918              }
2919              return false;
2920            };
2921
2922          events[type] = [];
2923
2924          // Refer to jQuery's implementation of mouseenter & mouseleave
2925          // Read about mouseenter and mouseleave:
2926          // http://www.quirksmode.org/js/events_mouse.html#link8
2927          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2928
2929          onFn(element, eventmap[type], function(event) {
2930            var target = this, related = event.relatedTarget;
2931            // For mousenter/leave call the handler if related is outside the target.
2932            // NB: No relatedTarget if the mouse left/entered the browser window
2933            if ( !related || (related !== target && !contains(target, related)) ){
2934              handle(event, type);
2935            }
2936          });
2937
2938        } else {
2939          addEventListenerFn(element, type, handle);
2940          events[type] = [];
2941        }
2942        eventFns = events[type];
2943      }
2944      eventFns.push(fn);
2945    });
2946  },
2947
2948  off: jqLiteOff,
2949
2950  one: function(element, type, fn) {
2951    element = jqLite(element);
2952
2953    //add the listener twice so that when it is called
2954    //you can remove the original function and still be
2955    //able to call element.off(ev, fn) normally
2956    element.on(type, function onFn() {
2957      element.off(type, fn);
2958      element.off(type, onFn);
2959    });
2960    element.on(type, fn);
2961  },
2962
2963  replaceWith: function(element, replaceNode) {
2964    var index, parent = element.parentNode;
2965    jqLiteDealoc(element);
2966    forEach(new JQLite(replaceNode), function(node){
2967      if (index) {
2968        parent.insertBefore(node, index.nextSibling);
2969      } else {
2970        parent.replaceChild(node, element);
2971      }
2972      index = node;
2973    });
2974  },
2975
2976  children: function(element) {
2977    var children = [];
2978    forEach(element.childNodes, function(element){
2979      if (element.nodeType === 1)
2980        children.push(element);
2981    });
2982    return children;
2983  },
2984
2985  contents: function(element) {
2986    return element.contentDocument || element.childNodes || [];
2987  },
2988
2989  append: function(element, node) {
2990    forEach(new JQLite(node), function(child){
2991      if (element.nodeType === 1 || element.nodeType === 11) {
2992        element.appendChild(child);
2993      }
2994    });
2995  },
2996
2997  prepend: function(element, node) {
2998    if (element.nodeType === 1) {
2999      var index = element.firstChild;
3000      forEach(new JQLite(node), function(child){
3001        element.insertBefore(child, index);
3002      });
3003    }
3004  },
3005
3006  wrap: function(element, wrapNode) {
3007    wrapNode = jqLite(wrapNode)[0];
3008    var parent = element.parentNode;
3009    if (parent) {
3010      parent.replaceChild(wrapNode, element);
3011    }
3012    wrapNode.appendChild(element);
3013  },
3014
3015  remove: function(element) {
3016    jqLiteDealoc(element);
3017    var parent = element.parentNode;
3018    if (parent) parent.removeChild(element);
3019  },
3020
3021  after: function(element, newElement) {
3022    var index = element, parent = element.parentNode;
3023    forEach(new JQLite(newElement), function(node){
3024      parent.insertBefore(node, index.nextSibling);
3025      index = node;
3026    });
3027  },
3028
3029  addClass: jqLiteAddClass,
3030  removeClass: jqLiteRemoveClass,
3031
3032  toggleClass: function(element, selector, condition) {
3033    if (selector) {
3034      forEach(selector.split(' '), function(className){
3035        var classCondition = condition;
3036        if (isUndefined(classCondition)) {
3037          classCondition = !jqLiteHasClass(element, className);
3038        }
3039        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3040      });
3041    }
3042  },
3043
3044  parent: function(element) {
3045    var parent = element.parentNode;
3046    return parent && parent.nodeType !== 11 ? parent : null;
3047  },
3048
3049  next: function(element) {
3050    if (element.nextElementSibling) {
3051      return element.nextElementSibling;
3052    }
3053
3054    // IE8 doesn't have nextElementSibling
3055    var elm = element.nextSibling;
3056    while (elm != null && elm.nodeType !== 1) {
3057      elm = elm.nextSibling;
3058    }
3059    return elm;
3060  },
3061
3062  find: function(element, selector) {
3063    if (element.getElementsByTagName) {
3064      return element.getElementsByTagName(selector);
3065    } else {
3066      return [];
3067    }
3068  },
3069
3070  clone: jqLiteClone,
3071
3072  triggerHandler: function(element, event, extraParameters) {
3073
3074    var dummyEvent, eventFnsCopy, handlerArgs;
3075    var eventName = event.type || event;
3076    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
3077
3078    if (eventFns) {
3079
3080      // Create a dummy event to pass to the handlers
3081      dummyEvent = {
3082        preventDefault: function() { this.defaultPrevented = true; },
3083        isDefaultPrevented: function() { return this.defaultPrevented === true; },
3084        stopPropagation: noop,
3085        type: eventName,
3086        target: element
3087      };
3088
3089      // If a custom event was provided then extend our dummy event with it
3090      if (event.type) {
3091        dummyEvent = extend(dummyEvent, event);
3092      }
3093
3094      // Copy event handlers in case event handlers array is modified during execution.
3095      eventFnsCopy = shallowCopy(eventFns);
3096      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3097
3098      forEach(eventFnsCopy, function(fn) {
3099        fn.apply(element, handlerArgs);
3100      });
3101
3102    }
3103  }
3104}, function(fn, name){
3105  /**
3106   * chaining functions
3107   */
3108  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3109    var value;
3110    for(var i=0; i < this.length; i++) {
3111      if (isUndefined(value)) {
3112        value = fn(this[i], arg1, arg2, arg3);
3113        if (isDefined(value)) {
3114          // any function which returns a value needs to be wrapped
3115          value = jqLite(value);
3116        }
3117      } else {
3118        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3119      }
3120    }
3121    return isDefined(value) ? value : this;
3122  };
3123
3124  // bind legacy bind/unbind to on/off
3125  JQLite.prototype.bind = JQLite.prototype.on;
3126  JQLite.prototype.unbind = JQLite.prototype.off;
3127});
3128
3129/**
3130 * Computes a hash of an 'obj'.
3131 * Hash of a:
3132 *  string is string
3133 *  number is number as string
3134 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3135 *         that is also assigned to the $$hashKey property of the object.
3136 *
3137 * @param obj
3138 * @returns {string} hash string such that the same input will have the same hash string.
3139 *         The resulting string key is in 'type:hashKey' format.
3140 */
3141function hashKey(obj, nextUidFn) {
3142  var objType = typeof obj,
3143      key;
3144
3145  if (objType == 'function' || (objType == 'object' && obj !== null)) {
3146    if (typeof (key = obj.$$hashKey) == 'function') {
3147      // must invoke on object to keep the right this
3148      key = obj.$$hashKey();
3149    } else if (key === undefined) {
3150      key = obj.$$hashKey = (nextUidFn || nextUid)();
3151    }
3152  } else {
3153    key = obj;
3154  }
3155
3156  return objType + ':' + key;
3157}
3158
3159/**
3160 * HashMap which can use objects as keys
3161 */
3162function HashMap(array, isolatedUid) {
3163  if (isolatedUid) {
3164    var uid = 0;
3165    this.nextUid = function() {
3166      return ++uid;
3167    };
3168  }
3169  forEach(array, this.put, this);
3170}
3171HashMap.prototype = {
3172  /**
3173   * Store key value pair
3174   * @param key key to store can be any type
3175   * @param value value to store can be any type
3176   */
3177  put: function(key, value) {
3178    this[hashKey(key, this.nextUid)] = value;
3179  },
3180
3181  /**
3182   * @param key
3183   * @returns {Object} the value for the key
3184   */
3185  get: function(key) {
3186    return this[hashKey(key, this.nextUid)];
3187  },
3188
3189  /**
3190   * Remove the key/value pair
3191   * @param key
3192   */
3193  remove: function(key) {
3194    var value = this[key = hashKey(key, this.nextUid)];
3195    delete this[key];
3196    return value;
3197  }
3198};
3199
3200/**
3201 * @ngdoc function
3202 * @module ng
3203 * @name angular.injector
3204 * @kind function
3205 *
3206 * @description
3207 * Creates an injector object that can be used for retrieving services as well as for
3208 * dependency injection (see {@link guide/di dependency injection}).
3209 *
3210
3211 * @param {Array.<string|Function>}
3211 modules A list of module functions or their aliases. See
3212 *        {@link angular.module}. The `ng` module must be explicitly added.
3213 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3214 *
3215 * @example
3216 * Typical usage
3217 * ```js
3218 *   // create an injector
3219 *   var $injector = angular.injector(['ng']);
3220 *
3221 *   // use the injector to kick off your application
3222 *   // use the type inference to auto inject arguments, or use implicit injection
3223 *   $injector.invoke(function($rootScope, $compile, $document){
3224 *     $compile($document)($rootScope);
3225 *     $rootScope.$digest();
3226 *   });
3227 * ```
3228 *
3229 * Sometimes you want to get access to the injector of a currently running Angular app
3230 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3231 * application has been bootstrapped. You can do this using the extra `injector()` added
3232 * to JQuery/jqLite elements. See {@link angular.element}.
3233 *
3234 * *This is fairly rare but could be the case if a third party library is injecting the
3235 * markup.*
3236 *
3237 * In the following example a new block of HTML containing a `ng-controller`
3238 * directive is added to the end of the document body by JQuery. We then compile and link
3239 * it into the current AngularJS scope.
3240 *
3241 * ```js
3242 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3243 * $(document.body).append($div);
3244 *
3245 * angular.element(document).injector().invoke(function($compile) {
3246 *   var scope = angular.element($div).scope();
3247 *   $compile($div)(scope);
3248 * });
3249 * ```
3250 */
3251
3252
3253/**
3254 * @ngdoc module
3255 * @name auto
3256 * @description
3257 *
3258 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3259 */
3260
3261var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3262var FN_ARG_SPLIT = /,/;
3263var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3264var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3265var $injectorMinErr = minErr('$injector');
3266function annotate(fn) {
3267  var $inject,
3268      fnText,
3269      argDecl,
3270      last;
3271
3272  if (typeof fn === 'function') {
3273    if (!($inject = fn.$inject)) {
3274      $inject = [];
3275      if (fn.length) {
3276        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3277        argDecl = fnText.match(FN_ARGS);
3278        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3279          arg.replace(FN_ARG, function(all, underscore, name){
3280            $inject.push(name);
3281          });
3282        });
3283      }
3284      fn.$inject = $inject;
3285    }
3286  } else if (isArray(fn)) {
3287    last = fn.length - 1;
3288    assertArgFn(fn[last], 'fn');
3289    $inject = fn.slice(0, last);
3290  } else {
3291    assertArgFn(fn, 'fn', true);
3292  }
3293  return $inject;
3294}
3295
3296///////////////////////////////////////
3297
3298/**
3299 * @ngdoc service
3300 * @name $injector
3301 *
3302 * @description
3303 *
3304 * `$injector` is used to retrieve object instances as defined by
3305 * {@link auto.$provide provider}, instantiate types, invoke methods,
3306 * and load modules.
3307 *
3308 * The following always holds true:
3309 *
3310 * ```js
3311 *   var $injector = angular.injector();
3312 *   expect($injector.get('$injector')).toBe($injector);
3313 *   expect($injector.invoke(function($injector){
3314 *     return $injector;
3315 *   })).toBe($injector);
3316 * ```
3317 *
3318 * # Injection Function Annotation
3319 *
3320 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3321 * following are all valid ways of annotating function with injection arguments and are equivalent.
3322 *
3323 * ```js
3324 *   // inferred (only works if code not minified/obfuscated)
3325 *   $injector.invoke(function(serviceA){});
3326 *
3327 *   // annotated
3328 *   function explicit(serviceA) {};
3329 *   explicit.$inject = ['serviceA'];
3330 *   $injector.invoke(explicit);
3331 *
3332 *   // inline
3333 *   $injector.invoke(['serviceA', function(serviceA){}]);
3334 * ```
3335 *
3336 * ## Inference
3337 *
3338 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3339 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3340 * minification, and obfuscation tools since these tools change the argument names.
3341 *
3342 * ## `$inject` Annotation
3343 * By adding an `$inject` property onto a function the injection parameters can be specified.
3344 *
3345 * ## Inline
3346 * As an array of injection names, where the last item in the array is the function to call.
3347 */
3348
3349/**
3350 * @ngdoc method
3351 * @name $injector#get
3352 *
3353 * @description
3354 * Return an instance of the service.
3355 *
3356 * @param {string} name The name of the instance to retrieve.
3357 * @return {*} The instance.
3358 */
3359
3360/**
3361 * @ngdoc method
3362 * @name $injector#invoke
3363 *
3364 * @description
3365 * Invoke the method and supply the method arguments from the `$injector`.
3366 *
3367 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3368 *   {@link guide/di $inject Annotation} rules.
3369 * @param {Object=} self The `this` for the invoked method.
3370 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3371 *                         object first, before the `$injector` is consulted.
3372 * @returns {*} the value returned by the invoked `fn` function.
3373 */
3374
3375/**
3376 * @ngdoc method
3377 * @name $injector#has
3378 *
3379 * @description
3380 * Allows the user to query if the particular service exists.
3381 *
3382 * @param {string} name Name of the service to query.
3383 * @returns {boolean} `true` if injector has given service.
3384 */
3385
3386/**
3387 * @ngdoc method
3388 * @name $injector#instantiate
3389 * @description
3390 * Create a new instance of JS type. The method takes a constructor function, invokes the new
3391 * operator, and supplies all of the arguments to the constructor function as specified by the
3392 * constructor annotation.
3393 *
3394 * @param {Function} Type Annotated constructor function.
3395 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3396 * object first, before the `$injector` is consulted.
3397 * @returns {Object} new instance of `Type`.
3398 */
3399
3400/**
3401 * @ngdoc method
3402 * @name $injector#annotate
3403 *
3404 * @description
3405 * Returns an array of service names which the function is requesting for injection. This API is
3406 * used by the injector to determine which services need to be injected into the function when the
3407 * function is invoked. There are three ways in which the function can be annotated with the needed
3408 * dependencies.
3409 *
3410 * # Argument names
3411 *
3412 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3413 * by converting the function into a string using `toString()` method and extracting the argument
3414 * names.
3415 * ```js
3416 *   // Given
3417 *   function MyController($scope, $route) {
3418 *     // ...
3419 *   }
3420 *
3421 *   // Then
3422 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3423 * ```
3424 *
3425 * This method does not work with code minification / obfuscation. For this reason the following
3426 * annotation strategies are supported.
3427 *
3428 * # The `$inject` property
3429 *
3430 * If a function has an `$inject` property and its value is an array of strings, then the strings
3431 * represent names of services to be injected into the function.
3432 * ```js
3433 *   // Given
3434 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3435 *     // ...
3436 *   }
3437 *   // Define function dependencies
3438 *   MyController['$inject'] = ['$scope', '$route'];
3439 *
3440 *   // Then
3441 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3442 * ```
3443 *
3444 * # The array notation
3445 *
3446 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3447 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3448 * a way that survives minification is a better choice:
3449 *
3450 * ```js
3451 *   // We wish to write this (not minification / obfuscation safe)
3452 *   injector.invoke(function($compile, $rootScope) {
3453 *     // ...
3454 *   });
3455 *
3456 *   // We are forced to write break inlining
3457 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3458 *     // ...
3459 *   };
3460 *   tmpFn.$inject = ['$compile', '$rootScope'];
3461 *   injector.invoke(tmpFn);
3462 *
3463 *   // To better support inline function the inline annotation is supported
3464 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3465 *     // ...
3466 *   }]);
3467 *
3468 *   // Therefore
3469 *   expect(injector.annotate(
3470 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3471 *    ).toEqual(['$compile', '$rootScope']);
3472 * ```
3473 *
3474 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3475 * be retrieved as described above.
3476 *
3477 * @returns {Array.<string>} The names of the services which the function requires.
3478 */
3479
3480
3481
3482
3483/**
3484 * @ngdoc service
3485 * @name $provide
3486 *
3487 * @description
3488 *
3489 * The {@link auto.$provide $provide} service has a number of methods for registering components
3490 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3491 * {@link angular.Module}.
3492 *
3493 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3494 * factories** are functions which, in turn, are created by a **service provider**.
3495 * The **service providers** are constructor functions. When instantiated they must contain a
3496 * property called `$get`, which holds the **service factory** function.
3497 *
3498 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3499 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3500 * function to get the instance of the **service**.
3501 *
3502 * Often services have no configuration options and there is no need to add methods to the service
3503 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3504 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3505 * services without specifying a provider.
3506 *
3507 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3508 *     {@link auto.$injector $injector}
3509 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3510 *     providers and services.
3511 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3512 *     services, not providers.
3513 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3514 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3515 *     given factory function.
3516 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3517 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3518 *      a new object using the given constructor function.
3519 *
3520 * See the individual methods for more information and examples.
3521 */
3522
3523/**
3524 * @ngdoc method
3525 * @name $provide#provider
3526 * @description
3527 *
3528 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3529 * are constructor functions, whose instances are responsible for "providing" a factory for a
3530 * service.
3531 *
3532 * Service provider names start with the name of the service they provide followed by `Provider`.
3533 * For example, the {@link ng.$log $log} service has a provider called
3534 * {@link ng.$logProvider $logProvider}.
3535 *
3536 * Service provider objects can have additional methods which allow configuration of the provider
3537 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3538 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3539 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3540 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3541 * console or not.
3542 *
3543 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3544                        'Provider'` key.
3545 * @param {(Object|function())} provider If the provider is:
3546 *
3547 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3548 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3549 *   - `Constructor`: a new instance of the provider will be created using
3550 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3551 *
3552 * @returns {Object} registered provider instance
3553
3554 * @example
3555 *
3556 * The following example shows how to create a simple event tracking service and register it using
3557 * {@link auto.$provide#provider $provide.provider()}.
3558 *
3559 * ```js
3560 *  // Define the eventTracker provider
3561 *  function EventTrackerProvider() {
3562 *    var trackingUrl = '/track';
3563 *
3564 *    // A provider method for configuring where the tracked events should been saved
3565 *    this.setTrackingUrl = function(url) {
3566 *      trackingUrl = url;
3567 *    };
3568 *
3569 *    // The service factory function
3570 *    this.$get = ['$http', function($http) {
3571 *      var trackedEvents = {};
3572 *      return {
3573 *        // Call this to track an event
3574 *        event: function(event) {
3575 *          var count = trackedEvents[event] || 0;
3576 *          count += 1;
3577 *          trackedEvents[event] = count;
3578 *          return count;
3579 *        },
3580 *        // Call this to save the tracked events to the trackingUrl
3581 *        save: function() {
3582 *          $http.post(trackingUrl, trackedEvents);
3583 *        }
3584 *      };
3585 *    }];
3586 *  }
3587 *
3588 *  describe('eventTracker', function() {
3589 *    var postSpy;
3590 *
3591 *    beforeEach(module(function($provide) {
3592 *      // Register the eventTracker provider
3593 *      $provide.provider('eventTracker', EventTrackerProvider);
3594 *    }));
3595 *
3596 *    beforeEach(module(function(eventTrackerProvider) {
3597 *      // Configure eventTracker provider
3598 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3599 *    }));
3600 *
3601 *    it('tracks events', inject(function(eventTracker) {
3602 *      expect(eventTracker.event('login')).toEqual(1);
3603 *      expect(eventTracker.event('login')).toEqual(2);
3604 *    }));
3605 *
3606 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3607 *      postSpy = spyOn($http, 'post');
3608 *      eventTracker.event('login');
3609 *      eventTracker.save();
3610 *      expect(postSpy).toHaveBeenCalled();
3611 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3612 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3613 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3614 *    }));
3615 *  });
3616 * ```
3617 */
3618
3619/**
3620 * @ngdoc method
3621 * @name $provide#factory
3622 * @description
3623 *
3624 * Register a **service factory**, which will be called to return the service instance.
3625 * This is short for registering a service where its provider consists of only a `$get` property,
3626 * which is the given service factory function.
3627 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3628 * configure your service in a provider.
3629 *
3630 * @param {string} name The name of the instance.
3631 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3632 *                            for `$provide.provider(name, {$get: $getFn})`.
3633 * @returns {Object} registered provider instance
3634 *
3635 * @example
3636 * Here is an example of registering a service
3637 * ```js
3638 *   $provide.factory('ping', ['$http', function($http) {
3639 *     return function ping() {
3640 *       return $http.send('/ping');
3641 *     };
3642 *   }]);
3643 * ```
3644 * You would then inject and use this service like this:
3645 * ```js
3646 *   someModule.controller('Ctrl', ['ping', function(ping) {
3647 *     ping();
3648 *   }]);
3649 * ```
3650 */
3651
3652
3653/**
3654 * @ngdoc method
3655 * @name $provide#service
3656 * @description
3657 *
3658 * Register a **service constructor**, which will be invoked with `new` to create the service
3659 * instance.
3660 * This is short for registering a service where its provider's `$get` property is the service
3661 * constructor function that will be used to instantiate the service instance.
3662 *
3663 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3664 * as a type/class.
3665 *
3666 * @param {string} name The name of the instance.
3667 * @param {Function} constructor A class (constructor function) that will be instantiated.
3668 * @returns {Object} registered provider instance
3669 *
3670 * @example
3671 * Here is an example of registering a service using
3672 * {@link auto.$provide#service $provide.service(class)}.
3673 * ```js
3674 *   var Ping = function($http) {
3675 *     this.$http = $http;
3676 *   };
3677 *
3678 *   Ping.$inject = ['$http'];
3679 *
3680 *   Ping.prototype.send = function() {
3681 *     return this.$http.get('/ping');
3682 *   };
3683 *   $provide.service('ping', Ping);
3684 * ```
3685 * You would then inject and use this service like this:
3686 * ```js
3687 *   someModule.controller('Ctrl', ['ping', function(ping) {
3688 *     ping.send();
3689 *   }]);
3690 * ```
3691 */
3692
3693
3694/**
3695 * @ngdoc method
3696 * @name $provide#value
3697 * @description
3698 *
3699 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3700 * number, an array, an object or a function.  This is short for registering a service where its
3701 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3702 * service**.
3703 *
3704 * Value services are similar to constant services, except that they cannot be injected into a
3705 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3706 * an Angular
3707 * {@link auto.$provide#decorator decorator}.
3708 *
3709 * @param {string} name The name of the instance.
3710 * @param {*} value The value.
3711 * @returns {Object} registered provider instance
3712 *
3713 * @example
3714 * Here are some examples of creating value services.
3715 * ```js
3716 *   $provide.value('ADMIN_USER', 'admin');
3717 *
3718 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3719 *
3720 *   $provide.value('halfOf', function(value) {
3721 *     return value / 2;
3722 *   });
3723 * ```
3724 */
3725
3726
3727/**
3728 * @ngdoc method
3729 * @name $provide#constant
3730 * @description
3731 *
3732 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3733 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3734 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3735 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3736 *
3737 * @param {string} name The name of the constant.
3738 * @param {*} value The constant value.
3739 * @returns {Object} registered instance
3740 *
3741 * @example
3742 * Here a some examples of creating constants:
3743 * ```js
3744 *   $provide.constant('SHARD_HEIGHT', 306);
3745 *
3746 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3747 *
3748 *   $provide.constant('double', function(value) {
3749 *     return value * 2;
3750 *   });
3751 * ```
3752 */
3753
3754
3755/**
3756 * @ngdoc method
3757 * @name $provide#decorator
3758 * @description
3759 *
3760 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3761 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3762 * service. The object returned by the decorator may be the original service, or a new service
3763 * object which replaces or wraps and delegates to the original service.
3764 *
3765 * @param {string} name The name of the service to decorate.
3766 * @param {function()} decorator This function will be invoked when the service needs to be
3767 *    instantiated and should return the decorated service instance. The function is called using
3768 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3769 *    Local injection arguments:
3770 *
3771 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3772 *      decorated or delegated to.
3773 *
3774 * @example
3775 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3776 * calls to {@link ng.$log#error $log.warn()}.
3777 * ```js
3778 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3779 *     $delegate.warn = $delegate.error;
3780 *     return $delegate;
3781 *   }]);
3782 * ```
3783 */
3784
3785
3786function createInjector(modulesToLoad) {
3787  var INSTANTIATING = {},
3788      providerSuffix = 'Provider',
3789      path = [],
3790      loadedModules = new HashMap([], true),
3791      providerCache = {
3792        $provide: {
3793            provider: supportObject(provider),
3794            factory: supportObject(factory),
3795            service: supportObject(service),
3796            value: supportObject(value),
3797            constant: supportObject(constant),
3798            decorator: decorator
3799          }
3800      },
3801      providerInjector = (providerCache.$injector =
3802          createInternalInjector(providerCache, function() {
3803            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3804          })),
3805      instanceCache = {},
3806      instanceInjector = (instanceCache.$injector =
3807          createInternalInjector(instanceCache, function(servicename) {
3808            var provider = providerInjector.get(servicename + providerSuffix);
3809            return instanceInjector.invoke(provider.$get, provider);
3810          }));
3811
3812
3813  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3814
3815  return instanceInjector;
3816
3817  ////////////////////////////////////
3818  // $provider
3819  ////////////////////////////////////
3820
3821  function supportObject(delegate) {
3822    return function(key, value) {
3823      if (isObject(key)) {
3824        forEach(key, reverseParams(delegate));
3825      } else {
3826        return delegate(key, value);
3827      }
3828    };
3829  }
3830
3831  function provider(name, provider_) {
3832    assertNotHasOwnProperty(name, 'service');
3833    if (isFunction(provider_) || isArray(provider_)) {
3834      provider_ = providerInjector.instantiate(provider_);
3835    }
3836    if (!provider_.$get) {
3837      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3838    }
3839    return providerCache[name + providerSuffix] = provider_;
3840  }
3841
3842  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3843
3844  function service(name, constructor) {
3845    return factory(name, ['$injector', function($injector) {
3846      return $injector.instantiate(constructor);
3847    }]);
3848  }
3849
3850  function value(name, val) { return factory(name, valueFn(val)); }
3851
3852  function constant(name, value) {
3853    assertNotHasOwnProperty(name, 'constant');
3854    providerCache[name] = value;
3855    instanceCache[name] = value;
3856  }
3857
3858  function decorator(serviceName, decorFn) {
3859    var origProvider = providerInjector.get(serviceName + providerSuffix),
3860        orig$get = origProvider.$get;
3861
3862    origProvider.$get = function() {
3863      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3864      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3865    };
3866  }
3867
3868  ////////////////////////////////////
3869  // Module Loading
3870  ////////////////////////////////////
3871  function loadModules(modulesToLoad){
3872    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3873    forEach(modulesToLoad, function(module) {
3874      if (loadedModules.get(module)) return;
3875      loadedModules.put(module, true);
3876
3877      try {
3878        if (isString(module)) {
3879          moduleFn = angularModule(module);
3880          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3881
3882          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3883            var invokeArgs = invokeQueue[i],
3884                provider = providerInjector.get(invokeArgs[0]);
3885
3886            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3887          }
3888        } else if (isFunction(module)) {
3889            runBlocks.push(providerInjector.invoke(module));
3890        } else if (isArray(module)) {
3891            runBlocks.push(providerInjector.invoke(module));
3892        } else {
3893          assertArgFn(module, 'module');
3894        }
3895      } catch (e) {
3896        if (isArray(module)) {
3897          module = module[module.length - 1];
3898        }
3899        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3900          // Safari & FF's stack traces don't contain error.message content
3901          // unlike those of Chrome and IE
3902          // So if stack doesn't contain message, we create a new string that contains both.
3903          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3904          /* jshint -W022 */
3905          e = e.message + '\n' + e.stack;
3906        }
3907        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3908                  module, e.stack || e.message || e);
3909      }
3910    });
3911    return runBlocks;
3912  }
3913
3914  ////////////////////////////////////
3915  // internal Injector
3916  ////////////////////////////////////
3917
3918  function createInternalInjector(cache, factory) {
3919
3920    function getService(serviceName) {
3921      if (cache.hasOwnProperty(serviceName)) {
3922        if (cache[serviceName] === INSTANTIATING) {
3923          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
3924                    serviceName + ' <- ' + path.join(' <- '));
3925        }
3926        return cache[serviceName];
3927      } else {
3928        try {
3929          path.unshift(serviceName);
3930          cache[serviceName] = INSTANTIATING;
3931          return cache[serviceName] = factory(serviceName);
3932        } catch (err) {
3933          if (cache[serviceName] === INSTANTIATING) {
3934            delete cache[serviceName];
3935          }
3936          throw err;
3937        } finally {
3938          path.shift();
3939        }
3940      }
3941    }
3942
3943    function invoke(fn, self, locals){
3944      var args = [],
3945          $inject = annotate(fn),
3946          length, i,
3947          key;
3948
3949      for(i = 0, length = $inject.length; i < length; i++) {
3950        key = $inject[i];
3951        if (typeof key !== 'string') {
3952          throw $injectorMinErr('itkn',
3953                  'Incorrect injection token! Expected service name as string, got {0}', key);
3954        }
3955        args.push(
3956          locals && locals.hasOwnProperty(key)
3957          ? locals[key]
3958          : getService(key)
3959        );
3960      }
3961      if (isArray(fn)) {
3962        fn = fn[length];
3963      }
3964
3965      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3966      // #5388
3967      return fn.apply(self, args);
3968    }
3969
3970    function instantiate(Type, locals) {
3971      var Constructor = function() {},
3972          instance, returnedValue;
3973
3974      // Check if Type is annotated and use just the given function at n-1 as parameter
3975      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3976      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3977      instance = new Constructor();
3978      returnedValue = invoke(Type, instance, locals);
3979
3980      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3981    }
3982
3983    return {
3984      invoke: invoke,
3985      instantiate: instantiate,
3986      get: getService,
3987      annotate: annotate,
3988      has: function(name) {
3989        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3990      }
3991    };
3992  }
3993}
3994
3995/**
3996 * @ngdoc service
3997 * @name $anchorScroll
3998 * @kind function
3999 * @requires $window
4000 * @requires $location
4001 * @requires $rootScope
4002 *
4003 * @description
4004 * When called, it checks current value of `$location.hash()` and scrolls to the related element,
4005 * according to rules specified in
4006 * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4007 *
4008 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
4009 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
4010 *
4011 * @example
4012   <example>
4013     <file name="index.html">
4014       <div id="scrollArea" ng-controller="ScrollCtrl">
4015         <a ng-click="gotoBottom()">Go to bottom</a>
4016         <a id="bottom"></a> You're at the bottom!
4017       </div>
4018     </file>
4019     <file name="script.js">
4020       function ScrollCtrl($scope, $location, $anchorScroll) {
4021         $scope.gotoBottom = function (){
4022           // set the location.hash to the id of
4023           // the element you wish to scroll to.
4024           $location.hash('bottom');
4025
4026           // call $anchorScroll()
4027           $anchorScroll();
4028         };
4029       }
4030     </file>
4031     <file name="style.css">
4032       #scrollArea {
4033         height: 350px;
4034         overflow: auto;
4035       }
4036
4037       #bottom {
4038         display: block;
4039         margin-top: 2000px;
4040       }
4041     </file>
4042   </example>
4043 */
4044function $AnchorScrollProvider() {
4045
4046  var autoScrollingEnabled = true;
4047
4048  /**
4049   * @ngdoc method
4050   * @name $anchorScrollProvider#disableAutoScrolling
4051   *
4052   * @description
4053   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4054   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4055   * Use this method to disable automatic scrolling.
4056   *
4057   * If automatic scrolling is disabled, one must explicitly call
4058   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4059   * current hash.
4060   */
4061  this.disableAutoScrolling = function() {
4062    autoScrollingEnabled = false;
4063  };
4064
4065  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4066    var document = $window.document;
4067
4068    // helper function to get first anchor from a NodeList
4069    // can't use filter.filter, as it accepts only instances of Array
4070    // and IE can't convert NodeList to an array using [].slice
4071    // TODO(vojta): use filter if we change it to accept lists as well
4072    function getFirstAnchor(list) {
4073      var result = null;
4074      forEach(list, function(element) {
4075        if (!result && lowercase(element.nodeName) === 'a') result = element;
4076      });
4077      return result;
4078    }
4079
4080    function scroll() {
4081      var hash = $location.hash(), elm;
4082
4083      // empty hash, scroll to the top of the page
4084      if (!hash) $window.scrollTo(0, 0);
4085
4086      // element with given id
4087      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4088
4089      // first anchor with given name :-D
4090      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4091
4092      // no element and hash == 'top', scroll to the top of the page
4093      else if (hash === 'top') $window.scrollTo(0, 0);
4094    }
4095
4096    // does not scroll when user clicks on anchor link that is currently on
4097    // (no url change, no $location.hash() change), browser native does scroll
4098    if (autoScrollingEnabled) {
4099      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4100        function autoScrollWatchAction() {
4101          $rootScope.$evalAsync(scroll);
4102        });
4103    }
4104
4105    return scroll;
4106  }];
4107}
4108
4109var $animateMinErr = minErr('$animate');
4110
4111/**
4112 * @ngdoc provider
4113 * @name $animateProvider
4114 *
4115 * @description
4116 * Default implementation of $animate that doesn't perform any animations, instead just
4117 * synchronously performs DOM
4118 * updates and calls done() callbacks.
4119 *
4120 * In order to enable animations the ngAnimate module has to be loaded.
4121 *
4122 * To see the functional implementation check out src/ngAnimate/animate.js
4123 */
4124var $AnimateProvider = ['$provide', function($provide) {
4125
4126
4127  this.$$selectors = {};
4128
4129
4130  /**
4131   * @ngdoc method
4132   * @name $animateProvider#register
4133   *
4134   * @description
4135   * Registers a new injectable animation factory function. The factory function produces the
4136   * animation object which contains callback functions for each event that is expected to be
4137   * animated.
4138   *
4139   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4140   *   must be called once the element animation is complete. If a function is returned then the
4141   *   animation service will use this function to cancel the animation whenever a cancel event is
4142   *   triggered.
4143   *
4144   *
4145   * ```js
4146   *   return {
4147     *     eventFn : function(element, done) {
4148     *       //code to run the animation
4149     *       //once complete, then run done()
4150     *       return function cancellationFunction() {
4151     *         //code to cancel the animation
4152     *       }
4153     *     }
4154     *   }
4155   * ```
4156   *
4157   * @param {string} name The name of the animation.
4158   * @param {Function} factory The factory function that will be executed to return the animation
4159   *                           object.
4160   */
4161  this.register = function(name, factory) {
4162    var key = name + '-animation';
4163    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4164        "Expecting class selector starting with '.' got '{0}'.", name);
4165    this.$$selectors[name.substr(1)] = key;
4166    $provide.factory(key, factory);
4167  };
4168
4169  /**
4170   * @ngdoc method
4171   * @name $animateProvider#classNameFilter
4172   *
4173   * @description
4174   * Sets and/or returns the CSS class regular expression that is checked when performing
4175   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4176   * therefore enable $animate to attempt to perform an animation on any element.
4177   * When setting the classNameFilter value, animations will only be performed on elements
4178   * that successfully match the filter expression. This in turn can boost performance
4179   * for low-powered devices as well as applications containing a lot of structural operations.
4180   * @param {RegExp=} expression The className expression which will be checked against all animations
4181   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4182   */
4183  this.classNameFilter = function(expression) {
4184    if(arguments.length === 1) {
4185      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4186    }
4187    return this.$$classNameFilter;
4188  };
4189
4190  this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
4191
4192    function async(fn) {
4193      fn && $$asyncCallback(fn);
4194    }
4195
4196    /**
4197     *
4198     * @ngdoc service
4199     * @name $animate
4200     * @description The $animate service provides rudimentary DOM manipulation functions to
4201     * insert, remove and move elements within the DOM, as well as adding and removing classes.
4202     * This service is the core service used by the ngAnimate $animator service which provides
4203     * high-level animation hooks for CSS and JavaScript.
4204     *
4205     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4206     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4207     * manipulation operations.
4208     *
4209     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4210     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4211     * page}.
4212     */
4213    return {
4214
4215      /**
4216       *
4217       * @ngdoc method
4218       * @name $animate#enter
4219       * @kind function
4220       * @description Inserts the element into the DOM either after the `after` element or within
4221       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4222       * @param {DOMElement} element the element which will be inserted into the DOM
4223       * @param {DOMElement} parent the parent element which will append the element as
4224       *   a child (if the after element is not present)
4225       * @param {DOMElement} after the sibling element which will append the element
4226       *   after itself
4227       * @param {Function=} done callback function that will be called after the element has been
4228       *   inserted into the DOM
4229       */
4230      enter : function(element, parent, after, done) {
4231        if (after) {
4232          after.after(element);
4233        } else {
4234          if (!parent || !parent[0]) {
4235            parent = after.parent();
4236          }
4237          parent.append(element);
4238        }
4239        async(done);
4240      },
4241
4242      /**
4243       *
4244       * @ngdoc method
4245       * @name $animate#leave
4246       * @kind function
4247       * @description Removes the element from the DOM. Once complete, the done() callback will be
4248       *   fired (if provided).
4249       * @param {DOMElement} element the element which will be removed from the DOM
4250       * @param {Function=} done callback function that will be called after the element has been
4251       *   removed from the DOM
4252       */
4253      leave : function(element, done) {
4254        element.remove();
4255        async(done);
4256      },
4257
4258      /**
4259       *
4260       * @ngdoc method
4261       * @name $animate#move
4262       * @kind function
4263       * @description Moves the position of the provided element within the DOM to be placed
4264       * either after the `after` element or inside of the `parent` element. Once complete, the
4265       * done() callback will be fired (if provided).
4266       *
4267       * @param {DOMElement} element the element which will be moved around within the
4268       *   DOM
4269       * @param {DOMElement} parent the parent element where the element will be
4270       *   inserted into (if the after element is not present)
4271       * @param {DOMElement} after the sibling element where the element will be
4272       *   positioned next to
4273       * @param {Function=} done the callback function (if provided) that will be fired after the
4274       *   element has been moved to its new position
4275       */
4276      move : function(element, parent, after, done) {
4277        // Do not remove element before insert. Removing will cause data associated with the
4278        // element to be dropped. Insert will implicitly do the remove.
4279        this.enter(element, parent, after, done);
4280      },
4281
4282      /**
4283       *
4284       * @ngdoc method
4285       * @name $animate#addClass
4286       * @kind function
4287       * @description Adds the provided className CSS class value to the provided element. Once
4288       * complete, the done() callback will be fired (if provided).
4289       * @param {DOMElement} element the element which will have the className value
4290       *   added to it
4291       * @param {string} className the CSS class which will be added to the element
4292       * @param {Function=} done the callback function (if provided) that will be fired after the
4293       *   className value has been added to the element
4294       */
4295      addClass : function(element, className, done) {
4296        className = isString(className) ?
4297                      className :
4298                      isArray(className) ? className.join(' ') : '';
4299        forEach(element, function (element) {
4300          jqLiteAddClass(element, className);
4301        });
4302        async(done);
4303      },
4304
4305      /**
4306       *
4307       * @ngdoc method
4308       * @name $animate#removeClass
4309       * @kind function
4310       * @description Removes the provided className CSS class value from the provided element.
4311       * Once complete, the done() callback will be fired (if provided).
4312       * @param {DOMElement} element the element which will have the className value
4313       *   removed from it
4314       * @param {string} className 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       *   className value has been removed from the element
4317       */
4318      removeClass : function(element, className, done) {
4319        className = isString(className) ?
4320                      className :
4321                      isArray(className) ? className.join(' ') : '';
4322        forEach(element, function (element) {
4323          jqLiteRemoveClass(element, className);
4324        });
4325        async(done);
4326      },
4327
4328      /**
4329       *
4330       * @ngdoc method
4331       * @name $animate#setClass
4332       * @kind function
4333       * @description Adds and/or removes the given CSS classes to and from the element.
4334       * Once complete, the done() callback will be fired (if provided).
4335       * @param {DOMElement} element the element which will have its CSS classes changed
4336       *   removed from it
4337       * @param {string} add the CSS classes which will be added to the element
4338       * @param {string} remove the CSS class which will be removed from the element
4339       * @param {Function=} done the callback function (if provided) that will be fired after the
4340       *   CSS classes have been set on the element
4341       */
4342      setClass : function(element, add, remove, done) {
4343        forEach(element, function (element) {
4344          jqLiteAddClass(element, add);
4345          jqLiteRemoveClass(element, remove);
4346        });
4347        async(done);
4348      },
4349
4350      enabled : noop
4351    };
4352  }];
4353}];
4354
4355function $$AsyncCallbackProvider(){
4356  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4357    return $$rAF.supported
4358      ? function(fn) { return $$rAF(fn); }
4359      : function(fn) {
4360        return $timeout(fn, 0, false);
4361      };
4362  }];
4363}
4364
4365/* global stripHash: true */
4366
4367/**
4368 * ! This is a private undocumented service !
4369 *
4370 * @name $browser
4371 * @requires $log
4372 * @description
4373 * This object has two goals:
4374 *
4375 * - hide all the global state in the browser caused by the window object
4376 * - abstract away all the browser specific features and inconsistencies
4377 *
4378 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4379 * service, which can be used for convenient testing of the application without the interaction with
4380 * the real browser apis.
4381 */
4382/**
4383 * @param {object} window The global window object.
4384 * @param {object} document jQuery wrapped document.
4385 * @param {function()} XHR XMLHttpRequest constructor.
4386 * @param {object} $log console.log or an object with the same interface.
4387 * @param {object} $sniffer $sniffer service
4388 */
4389function Browser(window, document, $log, $sniffer) {
4390  var self = this,
4391      rawDocument = document[0],
4392      location = window.location,
4393      history = window.history,
4394      setTimeout = window.setTimeout,
4395      clearTimeout = window.clearTimeout,
4396      pendingDeferIds = {};
4397
4398  self.isMock = false;
4399
4400  var outstandingRequestCount = 0;
4401  var outstandingRequestCallbacks = [];
4402
4403  // TODO(vojta): remove this temporary api
4404  self.$$completeOutstandingRequest = completeOutstandingRequest;
4405  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4406
4407  /**
4408   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4409   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4410   */
4411  function completeOutstandingRequest(fn) {
4412    try {
4413      fn.apply(null, sliceArgs(arguments, 1));
4414    } finally {
4415      outstandingRequestCount--;
4416      if (outstandingRequestCount === 0) {
4417        while(outstandingRequestCallbacks.length) {
4418          try {
4419            outstandingRequestCallbacks.pop()();
4420          } catch (e) {
4421            $log.error(e);
4422          }
4423        }
4424      }
4425    }
4426  }
4427
4428  function getHash(url) {
4429    var index = url.indexOf('#');
4430    return index === -1 ? '' : url.substr(index + 1);
4431  }
4432
4433  /**
4434   * @private
4435   * Note: this method is used only by scenario runner
4436   * TODO(vojta): prefix this method with $$ ?
4437   * @param {function()} callback Function that will be called when no outstanding request
4438   */
4439  self.notifyWhenNoOutstandingRequests = function(callback) {
4440    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4441    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4442    // regular poller would result in flaky tests.
4443    forEach(pollFns, function(pollFn){ pollFn(); });
4444
4445    if (outstandingRequestCount === 0) {
4446      callback();
4447    } else {
4448      outstandingRequestCallbacks.push(callback);
4449    }
4450  };
4451
4452  //////////////////////////////////////////////////////////////
4453  // Poll Watcher API
4454  //////////////////////////////////////////////////////////////
4455  var pollFns = [],
4456      pollTimeout;
4457
4458  /**
4459   * @name $browser#addPollFn
4460   *
4461   * @param {function()} fn Poll function to add
4462   *
4463   * @description
4464   * Adds a function to the list of functions that poller periodically executes,
4465   * and starts polling if not started yet.
4466   *
4467   * @returns {function()} the added function
4468   */
4469  self.addPollFn = function(fn) {
4470    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4471    pollFns.push(fn);
4472    return fn;
4473  };
4474
4475  /**
4476   * @param {number} interval How often should browser call poll functions (ms)
4477   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4478   *
4479   * @description
4480   * Configures the poller to run in the specified intervals, using the specified
4481   * setTimeout fn and kicks it off.
4482   */
4483  function startPoller(interval, setTimeout) {
4484    (function check() {
4485      forEach(pollFns, function(pollFn){ pollFn(); });
4486      pollTimeout = setTimeout(check, interval);
4487    })();
4488  }
4489
4490  //////////////////////////////////////////////////////////////
4491  // URL API
4492  //////////////////////////////////////////////////////////////
4493
4494  var lastBrowserUrl = location.href,
4495      baseElement = document.find('base'),
4496      reloadLocation = null;
4497
4498  /**
4499   * @name $browser#url
4500   *
4501   * @description
4502   * GETTER:
4503   * Without any argument, this method just returns current value of location.href.
4504   *
4505   * SETTER:
4506   * With at least one argument, this method sets url to new value.
4507   * If html5 history api supported, pushState/replaceState is used, otherwise
4508   * location.href/location.replace is used.
4509   * Returns its own instance to allow chaining
4510   *
4511   * NOTE: this api is intended for use only by the $location service. Please use the
4512   * {@link ng.$location $location service} to change url.
4513   *
4514   * @param {string} url New url (when used as setter)
4515   * @param {boolean=} replace Should new url replace current history record ?
4516   */
4517  self.url = function(url, replace) {
4518    // Android Browser BFCache causes location, history reference to become stale.
4519    if (location !== window.location) location = window.location;
4520    if (history !== window.history) history = window.history;
4521
4522    // setter
4523    if (url) {
4524      if (lastBrowserUrl == url) return;
4525      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
4526      lastBrowserUrl = url;
4527      // Don't use history API if only the hash changed
4528      // due to a bug in IE10/IE11 which leads
4529      // to not firing a `hashchange` nor `popstate` event
4530      // in some cases (see #9143).
4531      if (!sameBase && $sniffer.history) {
4532        if (replace) history.replaceState(null, '', url);
4533        else {
4534          history.pushState(null, '', url);
4535          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4536          baseElement.attr('href', baseElement.attr('href'));
4537        }
4538      } else {
4539        if (!sameBase) {
4540          reloadLocation = url;
4541        }
4542        if (replace) {
4543          location.replace(url);
4544        } else if (!sameBase) {
4545          location.href = url;
4546        } else {
4547          location.hash = getHash(url);
4548        }
4549      }
4550      return self;
4551    // getter
4552    } else {
4553      // - reloadLocation is needed as browsers don't allow to read out
4554      //   the new location.href if a reload happened.
4555      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4556      return reloadLocation || location.href.replace(/%27/g,"'");
4557    }
4558  };
4559
4560  var urlChangeListeners = [],
4561      urlChangeInit = false;
4562
4563  function fireUrlChange() {
4564    if (lastBrowserUrl == self.url()) return;
4565
4566    lastBrowserUrl = self.url();
4567    forEach(urlChangeListeners, function(listener) {
4568      listener(self.url());
4569    });
4570  }
4571
4572  /**
4573   * @name $browser#onUrlChange
4574   *
4575   * @description
4576   * Register callback function that will be called, when url changes.
4577   *
4578   * It's only called when the url is changed from outside of angular:
4579   * - user types different url into address bar
4580   * - user clicks on history (forward/back) button
4581   * - user clicks on a link
4582   *
4583   * It's not called when url is changed by $browser.url() method
4584   *
4585   * The listener gets called with new url as parameter.
4586   *
4587   * NOTE: this api is intended for use only by the $location service. Please use the
4588   * {@link ng.$location $location service} to monitor url changes in angular apps.
4589   *
4590   * @param {function(string)} listener Listener function to be called when url changes.
4591   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4592   */
4593  self.onUrlChange = function(callback) {
4594    // TODO(vojta): refactor to use node's syntax for events
4595    if (!urlChangeInit) {
4596      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4597      // don't fire popstate when user change the address bar and don't fire hashchange when url
4598      // changed by push/replaceState
4599
4600      // html5 history api - popstate event
4601      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4602      // hashchange event
4603      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4604      // polling
4605      else self.addPollFn(fireUrlChange);
4606
4607      urlChangeInit = true;
4608    }
4609
4610    urlChangeListeners.push(callback);
4611    return callback;
4612  };
4613
4614  /**
4615   * Checks whether the url has changed outside of Angular.
4616   * Needs to be exported to be able to check for changes that have been done in sync,
4617   * as hashchange/popstate events fire in async.
4618   */
4619  self.$$checkUrlChange = fireUrlChange;
4620
4621  //////////////////////////////////////////////////////////////
4622  // Misc API
4623  //////////////////////////////////////////////////////////////
4624
4625  /**
4626   * @name $browser#baseHref
4627   *
4628   * @description
4629   * Returns current <base href>
4630   * (always relative - without domain)
4631   *
4632   * @returns {string} The current base href
4633   */
4634  self.baseHref = function() {
4635    var href = baseElement.attr('href');
4636    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4637  };
4638
4639  //////////////////////////////////////////////////////////////
4640  // Cookies API
4641  //////////////////////////////////////////////////////////////
4642  var lastCookies = {};
4643  var lastCookieString = '';
4644  var cookiePath = self.baseHref();
4645
4646  /**
4647   * @name $browser#cookies
4648   *
4649   * @param {string=} name Cookie name
4650   * @param {string=} value Cookie value
4651   *
4652   * @description
4653   * The cookies method provides a 'private' low level access to browser cookies.
4654   * It is not meant to be used directly, use the $cookie service instead.
4655   *
4656   * The return values vary depending on the arguments that the method was called with as follows:
4657   *
4658   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4659   *   it
4660   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4661   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4662   *   way)
4663   *
4664   * @returns {Object} Hash of all cookies (if called without any parameter)
4665   */
4666  self.cookies = function(name, value) {
4667    /* global escape: false, unescape: false */
4668    var cookieLength, cookieArray, cookie, i, index;
4669
4670    if (name) {
4671      if (value === undefined) {
4672        rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
4673                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4674      } else {
4675        if (isString(value)) {
4676          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4677                                ';path=' + cookiePath).length + 1;
4678
4679          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4680          // - 300 cookies
4681          // - 20 cookies per unique domain
4682          // - 4096 bytes per cookie
4683          if (cookieLength > 4096) {
4684            $log.warn("Cookie '"+ name +
4685              "' possibly not set or overflowed because it was too large ("+
4686              cookieLength + " > 4096 bytes)!");
4687          }
4688        }
4689      }
4690    } else {
4691      if (rawDocument.cookie !== lastCookieString) {
4692        lastCookieString = rawDocument.cookie;
4693        cookieArray = lastCookieString.split("; ");
4694        lastCookies = {};
4695
4696        for (i = 0; i < cookieArray.length; i++) {
4697          cookie = cookieArray[i];
4698          index = cookie.indexOf('=');
4699          if (index > 0) { //ignore nameless cookies
4700            name = unescape(cookie.substring(0, index));
4701            // the first value that is seen for a cookie is the most
4702            // specific one.  values for the same cookie name that
4703            // follow are for less specific paths.
4704            if (lastCookies[name] === undefined) {
4705              lastCookies[name] = unescape(cookie.substring(index + 1));
4706            }
4707          }
4708        }
4709      }
4710      return lastCookies;
4711    }
4712  };
4713
4714
4715  /**
4716   * @name $browser#defer
4717   * @param {function()} fn A function, who's execution should be deferred.
4718   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4719   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4720   *
4721   * @description
4722   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4723   *
4724   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4725   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4726   * via `$browser.defer.flush()`.
4727   *
4728   */
4729  self.defer = function(fn, delay) {
4730    var timeoutId;
4731    outstandingRequestCount++;
4732    timeoutId = setTimeout(function() {
4733      delete pendingDeferIds[timeoutId];
4734      completeOutstandingRequest(fn);
4735    }, delay || 0);
4736    pendingDeferIds[timeoutId] = true;
4737    return timeoutId;
4738  };
4739
4740
4741  /**
4742   * @name $browser#defer.cancel
4743   *
4744   * @description
4745   * Cancels a deferred task identified with `deferId`.
4746   *
4747   * @param {*} deferId Token returned by the `$browser.defer` function.
4748   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4749   *                    canceled.
4750   */
4751  self.defer.cancel = function(deferId) {
4752    if (pendingDeferIds[deferId]) {
4753      delete pendingDeferIds[deferId];
4754      clearTimeout(deferId);
4755      completeOutstandingRequest(noop);
4756      return true;
4757    }
4758    return false;
4759  };
4760
4761}
4762
4763function $BrowserProvider(){
4764  this.$get = ['$window', '$log', '$sniffer', '$document',
4765      function( $window,   $log,   $sniffer,   $document){
4766        return new Browser($window, $document, $log, $sniffer);
4767      }];
4768}
4769
4770/**
4771 * @ngdoc service
4772 * @name $cacheFactory
4773 *
4774 * @description
4775 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4776 * them.
4777 *
4778 * ```js
4779 *
4780 *  var cache = $cacheFactory('cacheId');
4781 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4782 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4783 *
4784 *  cache.put("key", "value");
4785 *  cache.put("another key", "another value");
4786 *
4787 *  // We've specified no options on creation
4788 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4789 *
4790 * ```
4791 *
4792 *
4793 * @param {string} cacheId Name or id of the newly created cache.
4794 * @param {object=} options Options object that specifies the cache behavior. Properties:
4795 *
4796 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4797 *
4798 * @returns {object} Newly created cache object with the following set of methods:
4799 *
4800 * - `{object}` `info()` — Returns id, size, and options of cache.
4801 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4802 *   it.
4803 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4804 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4805 * - `{void}` `removeAll()` — Removes all cached values.
4806 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4807 *
4808 * @example
4809   <example module="cacheExampleApp">
4810     <file name="index.html">
4811       <div ng-controller="CacheController">
4812         <input ng-model="newCacheKey" placeholder="Key">
4813         <input ng-model="newCacheValue" placeholder="Value">
4814         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4815
4816         <p ng-if="keys.length">Cached Values</p>
4817         <div ng-repeat="key in keys">
4818           <span ng-bind="key"></span>
4819           <span>: </span>
4820           <b ng-bind="cache.get(key)"></b>
4821         </div>
4822
4823         <p>Cache Info</p>
4824         <div ng-repeat="(key, value) in cache.info()">
4825           <span ng-bind="key"></span>
4826           <span>: </span>
4827           <b ng-bind="value"></b>
4828         </div>
4829       </div>
4830     </file>
4831     <file name="script.js">
4832       angular.module('cacheExampleApp', []).
4833         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4834           $scope.keys = [];
4835           $scope.cache = $cacheFactory('cacheId');
4836           $scope.put = function(key, value) {
4837             if ($scope.cache.get(key) === undefined) {
4838               $scope.keys.push(key);
4839             }
4840             $scope.cache.put(key, value === undefined ? null : value);
4841           };
4842         }]);
4843     </file>
4844     <file name="style.css">
4845       p {
4846         margin: 10px 0 3px;
4847       }
4848     </file>
4849   </example>
4850 */
4851function $CacheFactoryProvider() {
4852
4853  this.$get = function() {
4854    var caches = {};
4855
4856    function cacheFactory(cacheId, options) {
4857      if (cacheId in caches) {
4858        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4859      }
4860
4861      var size = 0,
4862          stats = extend({}, options, {id: cacheId}),
4863          data = {},
4864          capacity = (options && options.capacity) || Number.MAX_VALUE,
4865          lruHash = {},
4866          freshEnd = null,
4867          staleEnd = null;
4868
4869      /**
4870       * @ngdoc type
4871       * @name $cacheFactory.Cache
4872       *
4873       * @description
4874       * A cache object used to store and retrieve data, primarily used by
4875       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4876       * templates and other data.
4877       *
4878       * ```js
4879       *  angular.module('superCache')
4880       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4881       *      return $cacheFactory('super-cache');
4882       *    }]);
4883       * ```
4884       *
4885       * Example test:
4886       *
4887       * ```js
4888       *  it('should behave like a cache', inject(function(superCache) {
4889       *    superCache.put('key', 'value');
4890       *    superCache.put('another key', 'another value');
4891       *
4892       *    expect(superCache.info()).toEqual({
4893       *      id: 'super-cache',
4894       *      size: 2
4895       *    });
4896       *
4897       *    superCache.remove('another key');
4898       *    expect(superCache.get('another key')).toBeUndefined();
4899       *
4900       *    superCache.removeAll();
4901       *    expect(superCache.info()).toEqual({
4902       *      id: 'super-cache',
4903       *      size: 0
4904       *    });
4905       *  }));
4906       * ```
4907       */
4908      return caches[cacheId] = {
4909
4910        /**
4911         * @ngdoc method
4912         * @name $cacheFactory.Cache#put
4913         * @kind function
4914         *
4915         * @description
4916         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4917         * retrieved later, and incrementing the size of the cache if the key was not already
4918         * present in the cache. If behaving like an LRU cache, it will also remove stale
4919         * entries from the set.
4920         *
4921         * It will not insert undefined values into the cache.
4922         *
4923         * @param {string} key the key under which the cached data is stored.
4924         * @param {*} value the value to store alongside the key. If it is undefined, the key
4925         *    will not be stored.
4926         * @returns {*} the value stored.
4927         */
4928        put: function(key, value) {
4929          if (capacity < Number.MAX_VALUE) {
4930            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4931
4932            refresh(lruEntry);
4933          }
4934
4935          if (isUndefined(value)) return;
4936          if (!(key in data)) size++;
4937          data[key] = value;
4938
4939          if (size > capacity) {
4940            this.remove(staleEnd.key);
4941          }
4942
4943          return value;
4944        },
4945
4946        /**
4947         * @ngdoc method
4948         * @name $cacheFactory.Cache#get
4949         * @kind function
4950         *
4951         * @description
4952         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4953         *
4954         * @param {string} key the key of the data to be retrieved
4955         * @returns {*} the value stored.
4956         */
4957        get: function(key) {
4958          if (capacity < Number.MAX_VALUE) {
4959            var lruEntry = lruHash[key];
4960
4961            if (!lruEntry) return;
4962
4963            refresh(lruEntry);
4964          }
4965
4966          return data[key];
4967        },
4968
4969
4970        /**
4971         * @ngdoc method
4972         * @name $cacheFactory.Cache#remove
4973         * @kind function
4974         *
4975         * @description
4976         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4977         *
4978         * @param {string} key the key of the entry to be removed
4979         */
4980        remove: function(key) {
4981          if (capacity < Number.MAX_VALUE) {
4982            var lruEntry = lruHash[key];
4983
4984            if (!lruEntry) return;
4985
4986            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4987            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4988            link(lruEntry.n,lruEntry.p);
4989
4990            delete lruHash[key];
4991          }
4992
4993          delete data[key];
4994          size--;
4995        },
4996
4997
4998        /**
4999         * @ngdoc method
5000         * @name $cacheFactory.Cache#removeAll
5001         * @kind function
5002         *
5003         * @description
5004         * Clears the cache object of any entries.
5005         */
5006        removeAll: function() {
5007          data = {};
5008          size = 0;
5009          lruHash = {};
5010          freshEnd = staleEnd = null;
5011        },
5012
5013
5014        /**
5015         * @ngdoc method
5016         * @name $cacheFactory.Cache#destroy
5017         * @kind function
5018         *
vendor: 6,188 bytes, lines 5019-5226
5019         * @description
5020         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
5021         * removing it from the {@link $cacheFactory $cacheFactory} set.
5022         */
5023        destroy: function() {
5024          data = null;
5025          stats = null;
5026          lruHash = null;
5027          delete caches[cacheId];
5028        },
5029
5030
5031        /**
5032         * @ngdoc method
5033         * @name $cacheFactory.Cache#info
5034         * @kind function
5035         *
5036         * @description
5037         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5038         *
5039         * @returns {object} an object with the following properties:
5040         *   <ul>
5041         *     <li>**id**: the id of the cache instance</li>
5042         *     <li>**size**: the number of entries kept in the cache instance</li>
5043         *     <li>**...**: any additional properties from the options object when creating the
5044         *       cache.</li>
5045         *   </ul>
5046         */
5047        info: function() {
5048          return extend({}, stats, {size: size});
5049        }
5050      };
5051
5052
5053      /**
5054       * makes the `entry` the freshEnd of the LRU linked list
5055       */
5056      function refresh(entry) {
5057        if (entry != freshEnd) {
5058          if (!staleEnd) {
5059            staleEnd = entry;
5060          } else if (staleEnd == entry) {
5061            staleEnd = entry.n;
5062          }
5063
5064          link(entry.n, entry.p);
5065          link(entry, freshEnd);
5066          freshEnd = entry;
5067          freshEnd.n = null;
5068        }
5069      }
5070
5071
5072      /**
5073       * bidirectionally links two entries of the LRU linked list
5074       */
5075      function link(nextEntry, prevEntry) {
5076        if (nextEntry != prevEntry) {
5077          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5078          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5079        }
5080      }
5081    }
5082
5083
5084  /**
5085   * @ngdoc method
5086   * @name $cacheFactory#info
5087   *
5088   * @description
5089   * Get information about all the caches that have been created
5090   *
5091   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5092   */
5093    cacheFactory.info = function() {
5094      var info = {};
5095      forEach(caches, function(cache, cacheId) {
5096        info[cacheId] = cache.info();
5097      });
5098      return info;
5099    };
5100
5101
5102  /**
5103   * @ngdoc method
5104   * @name $cacheFactory#get
5105   *
5106   * @description
5107   * Get access to a cache object by the `cacheId` used when it was created.
5108   *
5109   * @param {string} cacheId Name or id of a cache to access.
5110   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5111   */
5112    cacheFactory.get = function(cacheId) {
5113      return caches[cacheId];
5114    };
5115
5116
5117    return cacheFactory;
5118  };
5119}
5120
5121/**
5122 * @ngdoc service
5123 * @name $templateCache
5124 *
5125 * @description
5126 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5127 * can load templates directly into the cache in a `script` tag, or by consuming the
5128 * `$templateCache` service directly.
5129 *
5130 * Adding via the `script` tag:
5131 *
5132 * ```html
5133 *   <script type="text/ng-template" id="templateId.html">
5134 *     <p>This is the content of the template</p>
5135 *   </script>
5136 * ```
5137 *
5138 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5139 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
5140 * element with ng-app attribute), otherwise the template will be ignored.
5141 *
5142 * Adding via the $templateCache service:
5143 *
5144 * ```js
5145 * var myApp = angular.module('myApp', []);
5146 * myApp.run(function($templateCache) {
5147 *   $templateCache.put('templateId.html', 'This is the content of the template');
5148 * });
5149 * ```
5150 *
5151 * To retrieve the template later, simply use it in your HTML:
5152 * ```html
5153 * <div ng-include=" 'templateId.html' "></div>
5154 * ```
5155 *
5156 * or get it via Javascript:
5157 * ```js
5158 * $templateCache.get('templateId.html')
5159 * ```
5160 *
5161 * See {@link ng.$cacheFactory $cacheFactory}.
5162 *
5163 */
5164function $TemplateCacheProvider() {
5165  this.$get = ['$cacheFactory', function($cacheFactory) {
5166    return $cacheFactory('templates');
5167  }];
5168}
5169
5170/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5171 *
5172 * DOM-related variables:
5173 *
5174 * - "node" - DOM Node
5175 * - "element" - DOM Element or Node
5176 * - "$node" or "$element" - jqLite-wrapped node or element
5177 *
5178 *
5179 * Compiler related stuff:
5180 *
5181 * - "linkFn" - linking fn of a single directive
5182 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5183 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5184 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5185 */
5186
5187
5188/**
5189 * @ngdoc service
5190 * @name $compile
5191 * @kind function
5192 *
5193 * @description
5194 * Compiles an HTML string or DOM into a template and produces a template function, which
5195 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5196 *
5197 * The compilation is a process of walking the DOM tree and matching DOM elements to
5198 * {@link ng.$compileProvider#directive directives}.
5199 *
5200 * <div class="alert alert-warning">
5201 * **Note:** This document is an in-depth reference of all directive options.
5202 * For a gentle introduction to directives with examples of common use cases,
5203 * see the {@link guide/directive directive guide}.
5204 * </div>
5205 *
5206 * ## Comprehensive Directive API
5207 *
5208 * There are many different options for a directive.
5209 *
5210 * The difference resides in the return value of the factory function.
5211 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5212 * or just the `postLink` function (all other properties will have the default values).
5213 *
5214 * <div class="alert alert-success">
5215 * **Best Practice:** It's recommended to use the "directive definition object" form.
5216 * </div>
5217 *
5218 * Here's an example directive declared with a Directive Definition Object:
5219 *
5220 * ```js
5221 *   var myModule = angular.module(...);
5222 *
5223 *   myModule.directive('directiveName', function factory(injectables) {
5224 *     var directiveDefinitionObject = {
5225 *       priority: 0,
5226 *       template: '<div></div>
5226', // or // function(tElement, tAttrs) { ... },
5227 *       // or
5228 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5229 *       transclude: false,
5230 *       restrict: 'A',
5231 *       scope: false,
5232 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5233 *       controllerAs: 'stringAlias',
5234 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5235 *       compile: function compile(tElement, tAttrs, transclude) {
5236 *         return {
5237 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5238 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5239 *         }
5240 *         // or
5241 *         // return function postLink( ... ) { ... }
5242 *       },
5243 *       // or
5244 *       // link: {
5245 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5246 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5247 *       // }
5248 *       // or
5249 *       // link: function postLink( ... ) { ... }
5250 *     };
5251 *     return directiveDefinitionObject;
5252 *   });
5253 * ```
5254 *
5255 * <div class="alert alert-warning">
5256 * **Note:** Any unspecified options will use the default value. You can see the default values below.
5257 * </div>
5258 *
5259 * Therefore the above can be simplified as:
5260 *
5261 * ```js
5262 *   var myModule = angular.module(...);
5263 *
5264 *   myModule.directive('directiveName', function factory(injectables) {
5265 *     var directiveDefinitionObject = {
5266 *       link: function postLink(scope, iElement, iAttrs) { ... }
5267 *     };
5268 *     return directiveDefinitionObject;
5269 *     // or
5270 *     // return function postLink(scope, iElement, iAttrs) { ... }
5271 *   });
5272 * ```
5273 *
5274 *
5275 *
5276 * ### Directive Definition Object
5277 *
5278 * The directive definition object provides instructions to the {@link ng.$compile
5279 * compiler}. The attributes are:
5280 *
5281 * #### `priority`
5282 * When there are multiple directives defined on a single DOM element, sometimes it
5283 * is necessary to specify the order in which the directives are applied. The `priority` is used
5284 * to sort the directives before their `compile` functions get called. Priority is defined as a
5285 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5286 * are also run in priority order, but post-link functions are run in reverse order. The order
5287 * of directives with the same priority is undefined. The default priority is `0`.
5288 *
5289 * #### `terminal`
5290 * If set to true then the current `priority` will be the last set of directives
5291 * which will execute (any directives at the current priority will still execute
5292 * as the order of execution on same `priority` is undefined).
5293 *
5294 * #### `scope`
5295 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5296 * same element request a new scope, only one new scope is created. The new scope rule does not
5297 * apply for the root of the template since the root of the template always gets a new scope.
5298 *
5299 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5300 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5301 * when creating reusable components, which should not accidentally read or modify data in the
5302 * parent scope.
5303 *
5304 * The 'isolate' scope takes an object hash which defines a set of local scope properties
5305 * derived from the parent scope. These local properties are useful for aliasing values for
5306 * templates. Locals definition is a hash of local scope property to its source:
5307 *
5308 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5309 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5310 *   attribute name is assumed to be the same as the local name.
5311 *   Given `<widget my-attr="hello {{name}}">` and widget definition
5312 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5313 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5314 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5315 *   component scope).
5316 *
5317 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5318 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5319 *   name is specified then the attribute name is assumed to be the same as the local name.
5320 *   Given `<widget my-attr="parentModel">` and widget definition of
5321 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5322 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5323 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5324 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5325 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5326 *
5327 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5328 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5329 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5330 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5331 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5332 *   pass data from the isolated scope via an expression to the parent scope, this can be
5333 *   done by passing a map of local variable names and values into the expression wrapper fn.
5334 *   For example, if the expression is `increment(amount)` then we can specify the amount value
5335 *   by calling the `localFn` as `localFn({amount: 22})`.
5336 *
5337 *
5338 *
5339 * #### `controller`
5340 * Controller constructor function. The controller is instantiated before the
5341 * pre-linking phase and it is shared with other directives (see
5342 * `require` attribute). This allows the directives to communicate with each other and augment
5343 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5344 *
5345 * * `$scope` - Current scope associated with the element
5346 * * `$element` - Current element
5347 * * `$attrs` - Current attributes object for the element
5348 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5349 *    The scope can be overridden by an optional first argument.
5350 *   `function([scope], cloneLinkingFn)`.
5351 *
5352 *
5353 * #### `require`
5354 * Require another directive and inject its controller as the fourth argument to the linking function. The
5355 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5356 * injected argument will be an array in corresponding order. If no such directive can be
5357 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5358 *
5359 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5360 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5361 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5362 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5363 *   `null` to the `link` fn if not found.
5364 *
5365 *
5366 * #### `controllerAs`
5367 * Controller alias at the directive scope. An alias for the controller so it
5368 * can be referenced at the directive template. The directive needs to define a scope for this
5369 * configuration to be used. Useful in the case when directive is used as component.
5370 *
5371 *
5372 * #### `restrict`
5373 * String of subset of `EACM` which restricts the directive to a specific directive
5374 * declaration style. If omitted, the default (attributes only) is used.
5375 *
5376 * * `E` - Element name: `<my-directive></my-directive>`
5377 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5378 * * `C` - Class: `<div class="my-directive: exp;"></div>`
5379 * * `M` - Comment: `<!-- directive: my-directive exp -->`
5380 *
5381 *
5382 * #### `template`
5383 * HTML markup that may:
5384 * * Replace the contents of the directive's element (default).
5385 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
5386 * * Wrap the contents of the directive's element (if `transclude` is true).
5387 *
5388 * Value may be:
5389 *
5390 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
5391 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
5392 *   function api below) and returns a string value.
5393 *
5394 *
5395 * #### `templateUrl`
5396 * Same as `template` but the template is loaded from the specified URL. Because
5397 * the template loading is asynchronous the compilation/linking is suspended until the template
5398 * is loaded.
5399 *
5400 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5401 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5402 * a string value representing the url.  In either case, the template URL is passed through {@link
5403 * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5404 *
5405 *
5406 * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
5407 * specify what the template should replace. Defaults to `false`.
5408 *
5409 * * `true` - the template will replace the directive's element.
5410 * * `false` - the template will replace the contents of the directive's element.
5411 *
5412 * The replacement process migrates all of the attributes / classes from the old element to the new
5413 * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5414 * Directives Guide} for an example.
5415 *
5416 * #### `transclude`
5417 * compile the content of the element and make it available to the directive.
5418 * Typically used with {@link ng.directive:ngTransclude
5419 * ngTransclude}. The advantage of transclusion is that the linking function receives a
5420 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5421 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5422 * scope. This makes it possible for the widget to have private state, and the transclusion to
5423 * be bound to the parent (pre-`isolate`) scope.
5424 *
5425 * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
5426 * directive's element or the entire element:
5427 *
5428 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
5429 * * `'element'` - transclude the whole of the directive's element including any directives on this
5430 *   element that defined at a lower priority than this directive. When used, the `template`
5431 *   property is ignored.
5432 *
5433 * <div class="alert alert-warning">
5434 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
5435 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
5436 * Testing Transclusion Directives}.
5437 * </div>
5438 *
5439 * #### `compile`
5440 *
5441 * ```js
5442 *   function compile(tElement, tAttrs, transclude) { ... }
5443 * ```
5444 *
5445 * The compile function deals with transforming the template DOM. Since most directives do not do
5446 * template transformation, it is not used often. The compile function takes the following arguments:
5447 *
5448 *   * `tElement` - template element - The element where the directive has been declared. It is
5449 *     safe to do template transformation on the element and child elements only.
5450 *
5451 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5452 *     between all directive compile functions.
5453 *
5454 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5455 *
5456 * <div class="alert alert-warning">
5457 * **Note:** The template instance and the link instance may be different objects if the template has
5458 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5459 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5460 * should be done in a linking function rather than in a compile function.
5461 * </div>
5462
5463 * <div class="alert alert-warning">
5464 * **Note:** The compile function cannot handle directives that recursively use themselves in their
5465 * own templates or compile functions. Compiling these directives results in an infinite loop and a
5466 * stack overflow errors.
5467 *
5468 * This can be avoided by manually using $compile in the postLink function to imperatively compile
5469 * a directive's template instead of relying on automatic template compilation via `template` or
5470 * `templateUrl` declaration or manual compilation inside the compile function.
5471 * </div>
5472 *
5473 * <div class="alert alert-error">
5474 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5475 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5476 *   to the link function instead.
5477 * </div>
5478
5479 * A compile function can have a return value which can be either a function or an object.
5480 *
5481 * * returning a (post-link) function - is equivalent to registering the linking function via the
5482 *   `link` property of the config object when the compile function is empty.
5483 *
5484 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5485 *   control when a linking function should be called during the linking phase. See info about
5486 *   pre-linking and post-linking functions below.
5487 *
5488 *
5489 * #### `link`
5490 * This property is used only if the `compile` property is not defined.
5491 *
5492 * ```js
5493 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5494 * ```
5495 *
5496 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5497 * executed after the template has been cloned. This is where most of the directive logic will be
5498 * put.
5499 *
5500 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5501 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5502 *
5503 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5504 *     manipulate the children of the element only in `postLink` function since the children have
5505 *     already been linked.
5506 *
5507 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5508 *     between all directive linking functions.
5509 *
5510 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5511 *     element defines a controller. The controller is shared among all the directives, which allows
5512 *     the directives to use the controllers as a communication channel.
5513 *
5514 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5515 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5516 *     parameter of directive controllers.
5517 *     `function([scope], cloneLinkingFn)`.
5518 *
5519 *
5520 * #### Pre-linking function
5521 *
5522 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5523 * compiler linking function will fail to locate the correct elements for linking.
5524 *
5525 * #### Post-linking function
5526 *
5527 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5528 *
5529 * <a name="Attributes"></a>
5530 * ### Attributes
5531 *
5532 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5533 * `link()` or `compile()` functions. It has a variety of uses.
5534 *
5535 * accessing *Normalized attribute names:*
5536 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5537 * the attributes object allows for normalized access to
5538 *   the attributes.
5539 *
5540 * * *Directive inter-communication:* All directives share the same instance of the attributes
5541 *   object which allows the directives to use the attributes object as inter directive
5542 *   communication.
5543 *
5544 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5545 *   allowing other directives to read the interpolated value.
5546 *
5547 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5548 *   that contain interpolation (e.g. `src="{{bar}}
5548"`). Not only is this very efficient but it's also
5549 *   the only way to easily get the actual value because during the linking phase the interpolation
5550 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5551 *
5552 * ```js
5553 * function linkingFn(scope, elm, attrs, ctrl) {
5554 *   // get the attribute value
5555 *   console.log(attrs.ngModel);
5556 *
5557 *   // change the attribute
5558 *   attrs.$set('ngModel', 'new value');
5559 *
5560 *   // observe changes to interpolated attribute
5561 *   attrs.$observe('ngModel', function(value) {
5562 *     console.log('ngModel has changed value to ' + value);
5563 *   });
5564 * }
5565 * ```
5566 *
5567 * ## Example
5568 *
5569 * <div class="alert alert-warning">
5570 * **Note**: Typically directives are registered with `module.directive`. The example below is
5571 * to illustrate how `$compile` works.
5572 * </div>
5573 *
5574 <example module="compileExample">
5575   <file name="index.html">
5576    <script>
5577      angular.module('compileExample', [], function($compileProvider) {
5578        // configure new 'compile' directive by passing a directive
5579        // factory function. The factory function injects the '$compile'
5580        $compileProvider.directive('compile', function($compile) {
5581          // directive factory creates a link function
5582          return function(scope, element, attrs) {
5583            scope.$watch(
5584              function(scope) {
5585                 // watch the 'compile' expression for changes
5586                return scope.$eval(attrs.compile);
5587              },
5588              function(value) {
5589                // when the 'compile' expression changes
5590                // assign it into the current DOM
5591                element.html(value);
5592
5593                // compile the new DOM and link it to the current
5594                // scope.
5595                // NOTE: we only compile .childNodes so that
5596                // we don't get into infinite loop compiling ourselves
5597                $compile(element.contents())(scope);
5598              }
5599            );
5600          };
5601        });
5602      })
5603      .controller('GreeterController', ['$scope', function($scope) {
5604        $scope.name = 'Angular';
5605        $scope.html = 'Hello {{name}}';
5606      }]);
5607    </script>
5608    <div ng-controller="GreeterController">
5609      <input ng-model="name"> <br>
5610      <textarea ng-model="html"></textarea> <br>
5611      <div compile="html"></div>
5612    </div>
5613   </file>
5614   <file name="protractor.js" type="protractor">
5615     it('should auto compile', function() {
5616       var textarea = $('textarea');
5617       var output = $('div[compile]');
5618       // The initial state reads 'Hello Angular'.
5619       expect(output.getText()).toBe('Hello Angular');
5620       textarea.clear();
5621       textarea.sendKeys('{{name}}!');
5622       expect(output.getText()).toBe('Angular!');
5623     });
5624   </file>
5625 </example>
5626
5627 *
5628 *
5629 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5630 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5631 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5632 *                 root element(s), not their children)
5633 * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5634 * (a DOM element/tree) to a scope. Where:
5635 *
5636 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5637 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5638 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5639 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5640 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5641 *
5642 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5643 *      * `scope` - is the current scope with which the linking function is working with.
5644 *
5645 * Calling the linking function returns the element of the template. It is either the original
5646 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5647 *
5648 * After linking the view is not updated until after a call to $digest which typically is done by
5649 * Angular automatically.
5650 *
5651 * If you need access to the bound view, there are two ways to do it:
5652 *
5653 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5654 *   before you send them to the compiler and keep this reference around.
5655 *   ```js
5656 *     var element = $compile('<p>{{total}}</p>')(scope);
5657 *   ```
5658 *
5659 * - if on the other hand, you need the element to be cloned, the view reference from the original
5660 *   example would not point to the clone, but rather to the original template that was cloned. In
5661 *   this case, you can access the clone via the cloneAttachFn:
5662 *   ```js
5663 *     var templateElement = angular.element('<p>{{total}}</p>'),
5664 *         scope = ....;
5665 *
5666 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5667 *       //attach the clone to DOM document at the right place
5668 *     });
5669 *
5670 *     //now we have reference to the cloned DOM via `clonedElement`
5671 *   ```
5672 *
5673 *
5674 * For information on how the compiler works, see the
5675 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5676 */
5677
5678var $compileMinErr = minErr('$compile');
5679
5680/**
5681 * @ngdoc provider
5682 * @name $compileProvider
5683 * @kind function
5684 *
5685 * @description
5686 */
vendor: 4,560 bytes, lines 5687-5795
5687$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5688function $CompileProvider($provide, $$sanitizeUriProvider) {
5689  var hasDirectives = {},
5690      Suffix = 'Directive',
5691      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
5692      CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/;
5693
5694  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5695  // The assumption is that future DOM event attribute names will begin with
5696  // 'on' and be composed of only English letters.
5697  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5698
5699  /**
5700   * @ngdoc method
5701   * @name $compileProvider#directive
5702   * @kind function
5703   *
5704   * @description
5705   * Register a new directive with the compiler.
5706   *
5707   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5708   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5709   *    names and the values are the factories.
5710   * @param {Function|Array} directiveFactory An injectable directive factory function. See
5711   *    {@link guide/directive} for more info.
5712   * @returns {ng.$compileProvider} Self for chaining.
5713   */
5714   this.directive = function registerDirective(name, directiveFactory) {
5715    assertNotHasOwnProperty(name, 'directive');
5716    if (isString(name)) {
5717      assertArg(directiveFactory, 'directiveFactory');
5718      if (!hasDirectives.hasOwnProperty(name)) {
5719        hasDirectives[name] = [];
5720        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5721          function($injector, $exceptionHandler) {
5722            var directives = [];
5723            forEach(hasDirectives[name], function(directiveFactory, index) {
5724              try {
5725                var directive = $injector.invoke(directiveFactory);
5726                if (isFunction(directive)) {
5727                  directive = { compile: valueFn(directive) };
5728                } else if (!directive.compile && directive.link) {
5729                  directive.compile = valueFn(directive.link);
5730                }
5731                directive.priority = directive.priority || 0;
5732                directive.index = index;
5733                directive.name = directive.name || name;
5734                directive.require = directive.require || (directive.controller && directive.name);
5735                directive.restrict = directive.restrict || 'A';
5736                directives.push(directive);
5737              } catch (e) {
5738                $exceptionHandler(e);
5739              }
5740            });
5741            return directives;
5742          }]);
5743      }
5744      hasDirectives[name].push(directiveFactory);
5745    } else {
5746      forEach(name, reverseParams(registerDirective));
5747    }
5748    return this;
5749  };
5750
5751
5752  /**
5753   * @ngdoc method
5754   * @name $compileProvider#aHrefSanitizationWhitelist
5755   * @kind function
5756   *
5757   * @description
5758   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5759   * urls during a[href] sanitization.
5760   *
5761   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5762   *
5763   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5764   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5765   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5766   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5767   *
5768   * @param {RegExp=} regexp New regexp to whitelist urls with.
5769   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5770   *    chaining otherwise.
5771   */
5772  this.aHrefSanitizationWhitelist = function(regexp) {
5773    if (isDefined(regexp)) {
5774      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5775      return this;
5776    } else {
5777      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5778    }
5779  };
5780
5781
5782  /**
5783   * @ngdoc method
5784   * @name $compileProvider#imgSrcSanitizationWhitelist
5785   * @kind function
5786   *
5787   * @description
5788   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5789   * urls during img[src] sanitization.
5790   *
5791   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5792   *
5793   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5794   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5795   * regular expression. If a match is found, the original url is 
5795written into the dom. Otherwise,
5796   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5797   *
5798   * @param {RegExp=} regexp New regexp to whitelist urls with.
5799   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5800   *    chaining otherwise.
5801   */
5802  this.imgSrcSanitizationWhitelist = function(regexp) {
5803    if (isDefined(regexp)) {
5804      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5805      return this;
5806    } else {
5807      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5808    }
5809  };
5810
5811  this.$get = [
5812            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5813            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5814    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5815             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5816
5817    var Attributes = function(element, attr) {
5818      this.$$element = element;
5819      this.$attr = attr || {};
5820    };
5821
5822    Attributes.prototype = {
5823      /**
5824       * @ngdoc method
5825       * @name $compile.directive.Attributes#$normalize
5826       * @kind function
5827       *
5828       * @description
5829       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
5830       * `data-`) to its normalized, camelCase form.
5831       *
5832       * Also there is special case for Moz prefix starting with upper case letter.
5833       *
5834       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
5835       *
5836       * @param {string} name Name to normalize
5837       */
5838      $normalize: directiveNormalize,
5839
5840
5841      /**
5842       * @ngdoc method
5843       * @name $compile.directive.Attributes#$addClass
5844       * @kind function
5845       *
5846       * @description
5847       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5848       * are enabled then an animation will be triggered for the class addition.
5849       *
5850       * @param {string} classVal The className value that will be added to the element
5851       */
5852      $addClass : function(classVal) {
5853        if(classVal && classVal.length > 0) {
5854          $animate.addClass(this.$$element, classVal);
5855        }
5856      },
5857
5858      /**
5859       * @ngdoc method
5860       * @name $compile.directive.Attributes#$removeClass
5861       * @kind function
5862       *
5863       * @description
5864       * Removes the CSS class value specified by the classVal parameter from the element. If
5865       * animations are enabled then an animation will be triggered for the class removal.
5866       *
5867       * @param {string} classVal The className value that will be removed from the element
5868       */
5869      $removeClass : function(classVal) {
5870        if(classVal && classVal.length > 0) {
5871          $animate.removeClass(this.$$element, classVal);
5872        }
5873      },
5874
5875      /**
5876       * @ngdoc method
5877       * @name $compile.directive.Attributes#$updateClass
5878       * @kind function
5879       *
5880       * @description
5881       * Adds and removes the appropriate CSS class values to the element based on the difference
5882       * between the new and old CSS class values (specified as newClasses and oldClasses).
5883       *
5884       * @param {string} newClasses The current CSS className value
5885       * @param {string} oldClasses The former CSS className value
5886       */
5887      $updateClass : function(newClasses, oldClasses) {
5888        var toAdd = tokenDifference(newClasses, oldClasses);
5889        var toRemove = tokenDifference(oldClasses, newClasses);
5890
5891        if(toAdd.length === 0) {
5892          $animate.removeClass(this.$$element, toRemove);
5893        } else if(toRemove.length === 0) {
5894          $animate.addClass(this.$$element, toAdd);
5895        } else {
5896          $animate.setClass(this.$$element, toAdd, toRemove);
5897        }
5898      },
5899
5900      /**
5901       * Set a normalized attribute on the element in a way such that all directives
5902       * can share the attribute. This function properly handles boolean attributes.
5903       * @param {string} key Normalized key. (ie ngAttribute)
5904       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5905       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5906       *     Defaults to true.
5907       * @param {string=} attrName Optional none normalized name. Defaults to key.
5908       */
5909      $set: function(key, value, writeAttr, attrName) {
5910        // TODO: decide whether or not to throw an error if "class"
5911        //is set through this function since it may cause $updateClass to
5912        //become unstable.
5913
5914        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5915            normalizedVal,
5916            nodeName;
5917
5918        if (booleanKey) {
5919          this.$$element.prop(key, value);
5920          attrName = booleanKey;
5921        }
5922
5923        this[key] = value;
5924
5925        // translate normalized key to actual key
5926        if (attrName) {
5927          this.$attr[key] = attrName;
5928        } else {
5929          attrName = this.$attr[key];
5930          if (!attrName) {
5931            this.$attr[key] = attrName = snake_case(key, '-');
5932          }
5933        }
5934
5935        // SVG elements' `nodeName` can be lowercase
5936        nodeName = nodeName_(this.$$element).toUpperCase();
5937
5938        // sanitize a[href] and img[src] values
5939        if ((nodeName === 'A' && (key === 'href' || key === 'xlinkHref')) ||
5940            (nodeName === 'IMG' && key === 'src')) {
5941          this[key] = value = $$sanitizeUri(value, key === 'src');
5942        }
5943
5944        if (writeAttr !== false) {
5945          if (value === null || value === undefined) {
5946            this.$$element.removeAttr(attrName);
5947          } else {
5948            this.$$element.attr(attrName, value);
5949          }
5950        }
5951
5952        // fire observers
5953        var $$observers = this.$$observers;
5954        $$observers && forEach($$observers[key], function(fn) {
5955          try {
5956            fn(value);
5957          } catch (e) {
5958            $exceptionHandler(e);
5959          }
5960        });
5961      },
5962
5963
5964      /**
5965       * @ngdoc method
5966       * @name $compile.directive.Attributes#$observe
5967       * @kind function
5968       *
5969       * @description
5970       * Observes an interpolated attribute.
5971       *
5972       * The observer function will be invoked once during the next `$digest` following
5973       * compilation. The observer is then invoked whenever the interpolated value
5974       * changes.
5975       *
5976       * @param {string} key Normalized key. (ie ngAttribute) .
5977       * @param {function(interpolatedValue)} fn Function that will be called whenever
5978                the interpolated value of the attribute changes.
5979       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5980       * @returns {function()} the `fn` parameter.
5981       */
5982      $observe: function(key, fn) {
5983        var attrs = this,
5984            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5985            listeners = ($$observers[key] || ($$observers[key] = []));
5986
5987        listeners.push(fn);
5988        $rootScope.$evalAsync(function() {
5989          if (!listeners.$$inter) {
5990            // no one registered attribute interpolation function, so lets call it manually
5991            fn(attrs[key]);
5992          }
5993        });
5994        return fn;
5995      }
5996    };
5997
5998    var startSymbol = $interpolate.startSymbol(),
5999        endSymbol = $interpolate.endSymbol(),
6000        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
6001            ? identity
6002            : function denormalizeTemplate(template) {
6003              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
6004        },
6005        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
6006
6007
6008    return compile;
6009
6010    //================================
6011
6012    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
6013                        previousCompileContext) {
6014      if (!($compileNodes instanceof jqLite)) {
6015        // jquery always rewraps, whereas we need to preserve the original selector so that we can
6016        // modify it.
6017        $compileNodes = jqLite($compileNodes);
6018      }
6019      // We can not compile top level text elements since text nodes can be merged and we will
6020      // not be able to attach scope data to them, so we will wrap them in <span>
6021      forEach($compileNodes, function(node, index){
6022        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
6023          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
6024        }
6025      });
6026      var compositeLinkFn =
6027              compileNodes($compileNodes, transcludeFn, $compileNodes,
6028                           maxPriority, ignoreDirective, previousCompileContext);
6029      safeAddClass($compileNodes, 'ng-scope');
6030      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
6031        assertArg(scope, 'scope');
6032        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
6033        // and sometimes changes the structure of the DOM.
6034        var $linkNode = cloneConnectFn
6035          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
6036          : $compileNodes;
6037
6038        forEach(transcludeControllers, function(instance, name) {
6039          $linkNode.data('$' + name + 'Controller', instance);
6040        });
6041
6042        // Attach scope only to non-text nodes.
6043        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
6044          var node = $linkNode[i],
6045              nodeType = node.nodeType;
6046          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
6047            $linkNode.eq(i).data('$scope', scope);
6048          }
6049        }
6050
6051        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
6052        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
6053        return $linkNode;
6054      };
6055    }
6056
6057    function safeAddClass($element, className) {
vendor: 4,887 bytes, lines 6058-6168
6058      try {
6059        $element.addClass(className);
6060      } catch(e) {
6061        // ignore, since it means that we are trying to set class on
6062        // SVG element, where class name is read-only.
6063      }
6064    }
6065
6066    /**
6067     * Compile function matches each node in nodeList against the directives. Once all directives
6068     * for a particular node are collected their compile functions are executed. The compile
6069     * functions return values - the linking functions - are combined into a composite linking
6070     * function, which is the a linking function for the node.
6071     *
6072     * @param {NodeList} nodeList an array of nodes or NodeList to compile
6073     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6074     *        scope argument is auto-generated to the new child of the transcluded parent scope.
6075     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
6076     *        the rootElement must be set the jqLite collection of the compile root. This is
6077     *        needed so that the jqLite collection items can be replaced with widgets.
6078     * @param {number=} maxPriority Max directive priority.
6079     * @returns {Function} A composite linking function of all of the matched directives or null.
6080     */
6081    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
6082                            previousCompileContext) {
6083      var linkFns = [],
6084          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
6085
6086      for (var i = 0; i < nodeList.length; i++) {
6087        attrs = new Attributes();
6088
6089        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
6090        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
6091                                        ignoreDirective);
6092
6093        nodeLinkFn = (directives.length)
6094            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
6095                                      null, [], [], previousCompileContext)
6096            : null;
6097
6098        if (nodeLinkFn && nodeLinkFn.scope) {
6099          safeAddClass(attrs.$$element, 'ng-scope');
6100        }
6101
6102        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
6103                      !(childNodes = nodeList[i].childNodes) ||
6104                      !childNodes.length)
6105            ? null
6106            : compileNodes(childNodes,
6107                 nodeLinkFn ? (
6108                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
6109                     && nodeLinkFn.transclude) : transcludeFn);
6110
6111        linkFns.push(nodeLinkFn, childLinkFn);
6112        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
6113        //use the previous context only for the first element in the virtual group
6114        previousCompileContext = null;
6115      }
6116
6117      // return a linking function if we have found anything, null otherwise
6118      return linkFnFound ? compositeLinkFn : null;
6119
6120      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
6121        var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
6122
6123        // copy nodeList so that linking doesn't break due to live list updates.
6124        var nodeListLength = nodeList.length,
6125            stableNodeList = new Array(nodeListLength);
6126        for (i = 0; i < nodeListLength; i++) {
6127          stableNodeList[i] = nodeList[i];
6128        }
6129
6130        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
6131          node = stableNodeList[n];
6132          nodeLinkFn = linkFns[i++];
6133          childLinkFn = linkFns[i++];
6134
6135          if (nodeLinkFn) {
6136            if (nodeLinkFn.scope) {
6137              childScope = scope.$new();
6138              jqLite.data(node, '$scope', childScope);
6139            } else {
6140              childScope = scope;
6141            }
6142
6143            if ( nodeLinkFn.transcludeOnThisElement ) {
6144              childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
6145
6146            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
6147              childBoundTranscludeFn = parentBoundTranscludeFn;
6148
6149            } else if (!parentBoundTranscludeFn && transcludeFn) {
6150              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
6151
6152            } else {
6153              childBoundTranscludeFn = null;
6154            }
6155
6156            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
6157
6158          } else if (childLinkFn) {
6159            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
6160          }
6161        }
6162      }
6163    }
6164
6165    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
6166
6167      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
6168        var scopeCreated = false;
6169
6170        if (!transcludedScope) {
6171          transcludedScope = scope.$new();
6172          transcludedScope.$$transcluded = true;
6173          scopeCreated = true;
6174        }
6175
6176        var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
6177        if (scopeCreated) {
6178          clone.on('$destroy', function() { transcludedScope.$destroy(); });
6179        }
6180        return clone;
6181      };
6182
6183      return boundTranscludeFn;
6184    }
6185
6186    /**
6187     * Looks for directives on the given node and adds them to the directive collection which is
6188     * sorted.
6189     *
6190     * @param node Node to search.
6191     * @param directives An array to which the directives are added to. This array is sorted before
6192     *        the function returns.
6193     * @param attrs The shared attrs object which is used to populate the normalized attributes.
6194     * @param {number=} maxPriority Max directive priority.
6195     */
6196    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6197      var nodeType = node.nodeType,
6198          attrsMap = attrs.$attr,
6199          match,
6200          nodeName,
6201          className;
6202
6203      switch(nodeType) {
6204        case 1: /* Element */
6205
6206          nodeName = nodeName_(node).toLowerCase();
6207
6208          // use the node name: <directive>
6209          addDirective(directives,
6210              directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
6211
6212          // iterate over the attributes
6213          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
6214                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6215            var attrStartName = false;
6216            var attrEndName = false;
6217
6218            attr = nAttrs[j];
6219            if (!msie || msie >= 8 || attr.specified) {
6220              name = attr.name;
6221              value = trim(attr.value);
6222
6223              // support ngAttr attribute binding
6224              ngAttrName = directiveNormalize(name);
6225              if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
6226                name = snake_case(ngAttrName.substr(6), '-');
6227              }
6228
6229              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6230              if (ngAttrName === directiveNName + 'Start') {
6231                attrStartName = name;
6232                attrEndName = name.substr(0, name.length - 5) + 'end';
6233                name = name.substr(0, name.length - 6);
6234              }
6235
6236              nName = directiveNormalize(name.toLowerCase());
6237              attrsMap[nName] = name;
6238              if (isNgAttr || !attrs.hasOwnProperty(nName)) {
6239                  attrs[nName] = value;
6240                  if (getBooleanAttrName(node, nName)) {
6241                    attrs[nName] = true; // presence means true
6242                  }
6243              }
6244              addAttrInterpolateDirective(node, directives, value, nName);
6245              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6246                            attrEndName);
6247            }
6248          }
6249
6250          if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
6251            // Hidden input elements can have strange behaviour when navigating back to the page
6252            // This tells the browser not to try to cache and reinstate previous values
6253            node.setAttribute('autocomplete', 'off');
6254          }
6255
6256          // use class as directive
6257          className = node.className;
6258          if (isString(className) && className !== '') {
6259            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6260              nName = directiveNormalize(match[2]);
6261              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6262                attrs[nName] = trim(match[3]);
6263              }
6264              className = className.substr(match.index + match[0].length);
6265            }
6266          }
6267          break;
6268        case 3: /* Text Node */
6269          if (msie === 11) {
6270            // Workaround for #11781
6271            while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === 3 /* Text Node */) {
6272              node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
6273              node.parentNode.removeChild(node.nextSibling);
6274            }
6275          }
6276          addTextInterpolateDirective(directives, node.nodeValue);
6277          break;
6278        case 8: /* Comment */
6279          try {
6280            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6281            if (match) {
6282              nName = directiveNormalize(match[1]);
6283              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6284                attrs[nName] = trim(match[2]);
6285              }
6286            }
6287          } catch (e) {
6288            // turns out that under some circumstances IE9 throws errors when one attempts to read
6289            // comment's node value.
6290            // Just ignore it and continue. (Can't seem to reproduce in test case.)
6291          }
6292          break;
6293      }
6294
6295      directives.sort(byPriority);
6296      return directives;
6297    }
6298
6299    /**
6300     * Given a node with an directive-start it collects all of the siblings until it finds
6301     * directive-end.
6302     * @param node
6303     * @param attrStart
6304     * @param attrEnd
6305     * @returns {*}
6306     */
6307    function groupScan(node, attrStart, attrEnd) {
6308      var nodes = [];
6309      var depth = 0;
6310      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6311        var startNode = node;
6312        do {
6313          if (!node) {
6314            throw $compileMinErr('uterdir',
6315                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6316                      attrStart, attrEnd);
6317          }
6318          if (node.nodeType == 1 /** Element **/) {
6319            if (node.hasAttribute(attrStart)) depth++;
6320            if (node.hasAttribute(attrEnd)) depth--;
6321          }
6322          nodes.push(node);
6323          node = node.nextSibling;
6324        } while (depth > 0);
6325      } else {
6326        nodes.push(node);
6327      }
6328
6329      return jqLite(nodes);
6330    }
6331
6332    /**
6333     * Wrapper for linking function which converts normal linking function into a grouped
6334     * linking function.
6335     * @param linkFn
6336     * @param attrStart
6337     * @param attrEnd
6338     * @returns {Function}
6339     */
6340    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6341      return function(scope, element, attrs, controllers, transcludeFn) {
6342        element = groupScan(element[0], attrStart, attrEnd);
6343        return linkFn(scope, element, attrs, controllers, transcludeFn);
6344      };
6345    }
6346
6347    /**
6348     * Once the directives have been collected, their compile functions are executed. This method
6349     * is responsible for inlining directive templates as well as terminating the application
6350     * of the directives if the terminal directive has been reached.
6351     *
6352     * @param {Array} directives Array of collected directives to execute their compile function.
6353     *        this needs to be pre-sorted by priority order.
6354     * @param {Node} compileNode The raw DOM node to apply the compile functions to
6355     * @param {Object} templateAttrs The shared attribute function
6356     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6357     *                                                  scope argument is auto-generated to the new
6358     *                                                  child of the transcluded parent scope.
6359     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6360     *                              argument has the root jqLite array so that we can replace nodes
6361     *                              on it.
6362     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6363     *                                           compiling the transclusion.
6364     * @param {Array.<Function>} preLinkFns
6365     * @param {Array.<Function>} postLinkFns
6366     * @param {Object} previousCompileContext Context used for previous compilation of the current
6367     *                                        node
6368     * @returns {Function} linkFn
6369     */
6370    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
6371                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
6372                                   previousCompileContext) {
6373      previousCompileContext = previousCompileContext || {};
6374
6375      var terminalPriority = -Number.MAX_VALUE,
6376          newScopeDirective,
6377          controllerDirectives = previousCompileContext.controllerDirectives,
6378          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6379          templateDirective = previousCompileContext.templateDirective,
6380          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6381          hasTranscludeDirective = false,
6382          hasTemplate = false,
6383          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6384          $compileNode = templateAttrs.$$element = jqLite(compileNode),
6385          directive,
6386          directiveName,
6387          $template,
6388          replaceDirective = originalReplaceDirective,
6389          childTranscludeFn = transcludeFn,
6390          linkFn,
6391          directiveValue;
6392
6393      // executes all directives on the current element
6394      for(var i = 0, ii = directives.length; i < ii; i++) {
6395        directive = directives[i];
6396        var attrStart = directive.$$start;
6397        var attrEnd = directive.$$end;
6398
6399        // collect multiblock sections
6400        if (attrStart) {
6401          $compileNode = groupScan(compileNode, attrStart, attrEnd);
6402        }
6403        $template = undefined;
6404
6405        if (terminalPriority > directive.priority) {
6406          break; // prevent further processing of directives
6407        }
6408
6409        if (directiveValue = directive.scope) {
6410          newScopeDirective = newScopeDirective || directive;
6411
6412          // skip the check for directives with async templates, we'll check the derived sync
6413          // directive when the template arrives
6414          if (!directive.templateUrl) {
6415            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6416                              $compileNode);
6417            if (isObject(directiveValue)) {
6418              newIsolateScopeDirective = directive;
6419            }
6420          }
6421        }
6422
6423        directiveName = directive.name;
6424
6425        if (!directive.templateUrl && directive.controller) {
6426          directiveValue = directive.controller;
6427          controllerDirectives = controllerDirectives || {};
6428          assertNoDuplicate("'" + directiveName + "' controller",
6429              controllerDirectives[directiveName], directive, $compileNode);
6430          controllerDirectives[directiveName] = directive;
6431        }
6432
6433        if (directiveValue = directive.transclude) {
6434          hasTranscludeDirective = true;
6435
6436          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6437          // This option should only be used by directives that know how to safely handle element transclusion,
6438          // where the transcluded nodes are added or replaced after linking.
6439          if (!directive.$$tlb) {
6440            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6441            nonTlbTranscludeDirective = directive;
6442          }
6443
6444          if (directiveValue == 'element') {
6445            hasElementTranscludeDirective = true;
6446            terminalPriority = directive.priority;
6447            $template = $compileNode;
6448            $compileNode = templateAttrs.$$element =
6449                jqLite(document.createComment(' ' + directiveName + ': ' +
6450                                              templateAttrs[directiveName] + ' '));
6451            compileNode = $compileNode[0];
6452            replaceWith(jqCollection, sliceArgs($template), compileNode);
6453
6454            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6455                                        replaceDirective && replaceDirective.name, {
6456                                          // Don't pass in:
6457                                          // - controllerDirectives - otherwise we'll create duplicates controllers
6458                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 4,603 bytes, lines 6458-6565
6458ining templates with
6459                                          //   element transclusion doesn't make sense.
6460                                          //
6461                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6462                                          // on the same element more than once.
6463                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
6464                                        });
6465          } else {
6466            $template = jqLite(jqLiteClone(compileNode)).contents();
6467            $compileNode.empty(); // clear contents
6468            childTranscludeFn = compile($template, transcludeFn);
6469          }
6470        }
6471
6472        if (directive.template) {
6473          hasTemplate = true;
6474          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6475          templateDirective = directive;
6476
6477          directiveValue = (isFunction(directive.template))
6478              ? directive.template($compileNode, templateAttrs)
6479              : directive.template;
6480
6481          directiveValue = denormalizeTemplate(directiveValue);
6482
6483          if (directive.replace) {
6484            replaceDirective = directive;
6485            if (jqLiteIsTextNode(directiveValue)) {
6486              $template = [];
6487            } else {
6488              $template = jqLite(trim(directiveValue));
6489            }
6490            compileNode = $template[0];
6491
6492            if ($template.length != 1 || compileNode.nodeType !== 1) {
6493              throw $compileMinErr('tplrt',
6494                  "Template for directive '{0}' must have exactly one root element. {1}",
6495                  directiveName, '');
6496            }
6497
6498            replaceWith(jqCollection, $compileNode, compileNode);
6499
6500            var newTemplateAttrs = {$attr: {}};
6501
6502            // combine directives from the original node and from the template:
6503            // - take the array of directives for this element
6504            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6505            // - collect directives from the template and sort them by priority
6506            // - combine directives as: processed + template + unprocessed
6507            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6508            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6509
6510            if (newIsolateScopeDirective) {
6511              markDirectivesAsIsolate(templateDirectives);
6512            }
6513            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6514            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6515
6516            ii = directives.length;
6517          } else {
6518            $compileNode.html(directiveValue);
6519          }
6520        }
6521
6522        if (directive.templateUrl) {
6523          hasTemplate = true;
6524          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6525          templateDirective = directive;
6526
6527          if (directive.replace) {
6528            replaceDirective = directive;
6529          }
6530
6531          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6532              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
6533                controllerDirectives: controllerDirectives,
6534                newIsolateScopeDirective: newIsolateScopeDirective,
6535                templateDirective: templateDirective,
6536                nonTlbTranscludeDirective: nonTlbTranscludeDirective
6537              });
6538          ii = directives.length;
6539        } else if (directive.compile) {
6540          try {
6541            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6542            if (isFunction(linkFn)) {
6543              addLinkFns(null, linkFn, attrStart, attrEnd);
6544            } else if (linkFn) {
6545              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6546            }
6547          } catch (e) {
6548            $exceptionHandler(e, startingTag($compileNode));
6549          }
6550        }
6551
6552        if (directive.terminal) {
6553          nodeLinkFn.terminal = true;
6554          terminalPriority = Math.max(terminalPriority, directive.priority);
6555        }
6556
6557      }
6558
6559      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6560      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
6561      nodeLinkFn.templateOnThisElement = hasTemplate;
6562      nodeLinkFn.transclude = childTranscludeFn;
6563
6564      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6565
6566      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6567      return nodeLinkFn;
6568
6569      ////////////////////
6570
6571      function addLinkFns(pre, post, attrStart, attrEnd) {
6572        if (pre) {
6573          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6574          pre.require = directive.require;
6575          pre.directiveName = directiveName;
6576          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6577            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6578          }
6579          preLinkFns.push(pre);
6580        }
6581        if (post) {
6582          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6583          post.require = directive.require;
6584          post.directiveName = directiveName;
6585          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6586            post = cloneAndAnnotateFn(post, {isolateScope: true});
6587          }
6588          postLinkFns.push(post);
6589        }
6590      }
6591
6592
6593      function getControllers(directiveName, require, $element, elementControllers) {
6594        var value, retrievalMethod = 'data', optional = false;
6595        if (isString(require)) {
6596          while((value = require.charAt(0)) == '^' || value == '?') {
6597            require = require.substr(1);
6598            if (value == '^') {
6599              retrievalMethod = 'inheritedData';
6600            }
6601            optional = optional || value == '?';
6602          }
6603          value = null;
6604
6605          if (elementControllers && retrievalMethod === 'data') {
6606            value = elementControllers[require];
6607          }
6608          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6609
6610          if (!value && !optional) {
6611            throw $compileMinErr('ctreq',
6612                "Controller '{0}', required by directive '{1}', can't be found!",
6613                require, directiveName);
6614          }
6615          return value;
6616        } else if (isArray(require)) {
6617          value = [];
6618          forEach(require, function(require) {
6619            value.push(getControllers(directiveName, require, $element, elementControllers));
6620          });
6621        }
6622        return value;
6623      }
6624
6625
6626      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6627        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6628
6629        attrs = (compileNode === linkNode)
6630          ? templateAttrs
6631          : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6632        $element = attrs.$$element;
6633
6634        if (newIsolateScopeDirective) {
6635          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6636
6637          isolateScope = scope.$new(true);
6638
6639          if (templateDirective && (templateDirective === newIsolateScopeDirective ||
6640              templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6641            $element.data('$isolateScope', isolateScope);
6642          } else {
6643            $element.data('$isolateScopeNoTemplate', isolateScope);
6644          }
6645
6646
6647
6648          safeAddClass($element, 'ng-isolate-scope');
6649
6650          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6651            var match = definition.match(LOCAL_REGEXP) || [],
6652                attrName = match[3] || scopeName,
6653                optional = (match[2] == '?'),
6654                mode = match[1], // @, =, or &
6655                lastValue,
6656                parentGet, parentSet, compare;
6657
6658            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6659
6660            switch (mode) {
6661
6662              case '@':
6663                attrs.$observe(attrName, function(value) {
6664                  isolateScope[scopeName] = value;
6665                });
6666                attrs.$$observers[attrName].$$scope = scope;
6667                if( attrs[attrName] ) {
6668                  // If the attribute has been provided then we trigger an interpolation to ensure
6669                  // the value is there for use in the link fn
6670                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6671                }
6672                break;
6673
6674              case '=':
6675                if (optional && !attrs[attrName]) {
6676                  return;
6677                }
6678                parentGet = $parse(attrs[attrName]);
6679                if (parentGet.literal) {
6680                  compare = equals;
6681                } else {
6682                  compare = function(a,b) { return a === b || (a !== a && b !== b); };
6683                }
6684                parentSet = parentGet.assign || function() {
6685                  // reset the change, or we will throw this exception on every $digest
6686                  lastValue = isolateScope[scopeName] = parentGet(scope);
6687                  throw $compileMinErr('nonassign',
6688                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6689                      attrs[attrName], newIsolateScopeDirective.name);
6690                };
6691                lastValue = isolateScope[scopeName] = parentGet(scope);
6692                isolateScope.$watch(function parentValueWatch() {
6693                  var parentValue = parentGet(scope);
6694                  if (!compare(parentValue, isolateScope[scopeName])) {
6695                    // we are out of sync and need to copy
6696                    if (!compare(parentValue, lastValue)) {
6697                      // parent changed and it has precedence
6698                      isolateScope[scopeName] = parentValue;
6699                    } else {
6700                      // if the parent can be assigned then do so
6701                      parentSet(scope, parentValue = isolateScope[scopeName]);
6702                    }
6703                  }
6704                  return lastValue = parentValue;
6705                }, null, parentGet.literal);
6706                break;
6707
6708              case '&':
6709                parentGet = $parse(attrs[attrName]);
6710                isolateScope[scopeName] = function(locals) {
6711                  return parentGet(scope, locals);
6712                };
6713                break;
6714
6715              default:
6716                throw $compileMinErr('iscp',
6717                    "Invalid isolate scope definition for directive '{0}'." +
6718                    " Definition: {... {1}: '{2}' ...}",
6719                    newIsolateScopeDirective.name, scopeName, definition);
6720            }
6721          });
6722        }
6723        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6724        if (controllerDirectives) {
6725          forEach(controllerDirectives, function(directive) {
6726            var locals = {
6727              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6728              $element: $element,
6729              $attrs: attrs,
6730              $transclude: transcludeFn
6731            }, controllerInstance;
6732
6733            controller = directive.controller;
6734            if (controller == '@') {
6735              controller = attrs[directive.name];
6736            }
6737
6738            controllerInstance = $controller(controller, locals);
6739            // For directives with element transclusion the element is a comment,
6740            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6741            // clean up (http://bugs.jquery.com/ticket/8335).
6742            // Instead, we save the controllers for the element in a local hash and attach to .data
6743            // later, once we have the actual element.
6744            elementControllers[directive.name] = controllerInstance;
6745            if (!hasElementTranscludeDirective) {
6746              $element.data('$' + directive.name + 'Controller', controllerInstance);
6747            }
6748
6749            if (directive.controllerAs) {
6750              locals.$scope[directive.controllerAs] = controllerInstance;
6751            }
6752          });
6753        }
6754
6755        // PRELINKING
6756        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6757          try {
6758            linkFn = preLinkFns[i];
6759            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6760                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6761          } catch (e) {
6762            $exceptionHandler(e, startingTag($element));
6763          }
6764        }
6765
6766        // RECURSION
6767        // We only pass the isolate scope, if the isolate directive has a template,
6768        // otherwise the child elements do not belong to the isolate directive.
6769        var scopeToChild = scope;
6770        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6771          scopeToChild = isolateScope;
6772        }
6773        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6774
6775        // POSTLINKING
6776        for(i = postLinkFns.length - 1; i >= 0; i--) {
6777          try {
6778            linkFn = postLinkFns[i];
6779            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6780                linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn);
6781          } catch (e) {
6782            $exceptionHandler(e, startingTag($element));
6783          }
6784        }
6785
6786        // This is the function that is injected as `$transclude`.
6787        function controllersBoundTransclude(scope, cloneAttachFn) {
6788          var transcludeControllers;
6789
6790          // no scope passed
6791          if (arguments.length < 2) {
6792            cloneAttachFn = scope;
6793            scope = undefined;
6794          }
6795
6796          if (hasElementTranscludeDirective) {
6797            transcludeControllers = elementControllers;
6798          }
6799
6800          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6801        }
6802      }
6803    }
6804
6805    function markDirectivesAsIsolate(directives) {
6806      // mark all directives as needing isolate scope.
6807      for (var j = 0, jj = directives.length; j < jj; j++) {
6808        directives[j] = inherit(directives[j], {$$isolateScope: true});
6809      }
6810    }
6811
6812    /**
6813     * looks up the directive and decorates it with exception handling and proper parameters. We
6814     * call this the boundDirective.
6815     *
6816     * @param {string} name name of the directive to look up.
6817     * @param {string} location The directive must be found in specific format.
6818     *   String containing any of theses characters:
6819     *
6820     *   * `E`: element name
6821     *   * `A': attribute
6822     *   * `C`: class
6823     *   * `M`: comment
6824     * @returns {boolean} true if directive was added.
6825     */
6826    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6827                          endAttrName) {
6828      if (name === ignoreDirective) return null;
6829      var match = null;
6830      if (hasDirectives.hasOwnProperty(name)) {
6831        for(var directive, directives = $injector.get(name + Suffix),
6832            i = 0, ii = directives.length; i<ii; i++) {
6833          try {
6834            directive = directives[i];
6835            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6836                 directive.restrict.indexOf(location) != -1) {
6837              if (startAttrName) {
6838                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6839              }
6840              tDirectives.push(directive);
6841              match = directive;
6842            }
6843          } catch(e) { $exceptionHandler(e); }
6844        }
6845      }
6846      return match;
6847    }
6848
6849
6850    /**
6851     * When the element is replaced with HTML template then the new attributes
6852     * on the template need to be merged with the existing attributes in the DOM.
6853     * The desired effect is to have both of the attributes present.
6854     *
6855     * @param {object} dst destination attributes (original DOM)
6856     * @param {object} src source attributes (from the directive template)
6857     */
6858    function mergeTemplateAttributes(dst, src) {
6859      var srcAttr = src.$attr,
6860          dstAttr = dst.$attr,
6861          $element = dst.$$element;
6862
6863      // reapply the old attributes to the new element
6864      forEach(dst, function(value, key) {
6865        if (key.charAt(0) != '$') {
6866          if (src[key] && src[key] !== value) {
6867            value += (key === 'style' ? ';' : ' ') + src[key];
6868          }
6869          dst.$set(key, value, true, srcAttr[key]);
6870        }
6871      });
6872
6873      // copy the new attributes on the old attrs object
6874      forEach(src, function(value, key) {
6875        if (key == 'class') {
6876          safeAddClass($element, value);
6877          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6878        } else if (key == 'style') {
6879          $element.attr('style', $element.attr('style') + ';' + value);
6880          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6881          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6882          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6883          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6884        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6885          dst[key] = value;
6886          dstAttr[key] = srcAttr[key];
6887        }
6888      });
6889    }
6890
6891
6892    function compileTemplateUrl(directives, $compileNode, tAttrs,
6893        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6894      var linkQueue = [],
6895          afterTemplateNodeLinkFn,
6896          afterTemplateChildLinkFn,
6897          beforeTemplateCompileNode = $compileNode[0],
6898          origAsyncDirective = directives.shift(),
6899          // The fact that we have to copy and patch the directive seems wrong!
6900          derivedSyncDirective = extend({}, origAsyncDirective, {
6901            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6902          }),
6903          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6904              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
6905              : origAsyncDirective.templateUrl;
6906
6907      $compileNode.empty();
6908
6909      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6910        success(function(content) {
6911          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6912
6913          content = denormalizeTemplate(content);
6914
6915          if (origAsyncDirective.replace) {
6916            if (jqLiteIsTextNode(content)) {
6917              $template = [];
6918            } else {
6919              $template = jqLite(trim(content));
6920            }
6921            compileNode = $template[0];
6922
6923            if ($template.length != 1 || compileNode.nodeType !== 1) {
6924              throw $compileMinErr('tplrt',
6925                  "Template for directive '{0}' must have exactly one root element. {1}",
6926                  origAsyncDirective.name, templateUrl);
6927            }
6928
6929            tempTemplateAttrs = {$attr: {}};
6930            replaceWith($rootElement, $compileNode, compileNode);
6931            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6932
6933            if (isObject(origAsyncDirective.scope)) {
6934              markDirectivesAsIsolate(templateDirectives);
6935            }
6936            directives = templateDirectives.concat(directives);
6937            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6938          } else {
6939            compileNode = beforeTemplateCompileNode;
6940            $compileNode.html(content);
6941          }
6942
6943          directives.unshift(derivedSyncDirective);
6944
6945          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6946              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6947              previousCompileContext);
6948          forEach($rootElement, function(node, i) {
6949            if (node == compileNode) {
6950              $rootElement[i] = $compileNode[0];
6951            }
6952          });
6953          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6954
6955          while(linkQueue.length) {
6956            var scope = linkQueue.shift(),
6957                beforeTemplateLinkNode = linkQueue.shift(),
6958                linkRootElement = linkQueue.shift(),
6959                boundTranscludeFn = linkQueue.shift(),
6960                linkNode = $compileNode[0];
6961
6962            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6963              var oldClasses = beforeTemplateLinkNode.className;
6964
6965              if (!(previousCompileContext.hasElementTranscludeDirective &&
6966                  origAsyncDirective.replace)) {
6967                // it was cloned therefore we have to clone as well.
6968                linkNode = jqLiteClone(compileNode);
6969              }
6970
6971              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6972
6973              // Copy in CSS classes from original node
6974              safeAddClass(jqLite(linkNode), oldClasses);
6975            }
6976            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6977              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
6978            } else {
6979              childBoundTranscludeFn = boundTranscludeFn;
6980            }
6981            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6982              childBoundTranscludeFn);
6983          }
6984          linkQueue = null;
6985        }).
6986        error(function(response, code, headers, config) {
6987          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6988        });
6989
6990      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6991        var childBoundTranscludeFn = boundTranscludeFn;
6992        if (linkQueue) {
6993          linkQueue.push(scope);
6994          linkQueue.push(node);
6995          linkQueue.push(rootElement);
6996          linkQueue.push(childBoundTranscludeFn);
6997        } else {
6998          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
6999            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
7000          }
7001          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
7002        }
7003      };
7004    }
7005
7006
7007    /**
7008     * Sorting function for bound directives.
7009     */
7010    function byPriority(a, b) {
7011      var diff = b.priority - a.priority;
7012      if (diff !== 0) return diff;
7013      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
7014      return a.index - b.index;
7015    }
7016
7017
7018    function assertNoDuplicate(what, previousDirective, directive, element) {
7019      if (previousDirective) {
7020        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
7021            previousDirective.name, directive.name, what, startingTag(element));
7022      }
7023    }
7024
7025
7026      function addTextInterpolateDirective(directives, text) {
7027        var interpolateFn = $interpolate(text, true);
7028        if (interpolateFn) {
7029          directives.push({
7030            priority: 0,
7031            compile: function textInterpolateCompileFn(templateNode) {
7032              // when transcluding a template that has bindings in the root
7033              // then we don't have a parent and should do this in the linkFn
7034              var parent = templateNode.parent(), hasCompileParent = parent.length;
7035              if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding');
7036
7037              return function textInterpolateLinkFn(scope, node) {
7038                var parent = node.parent(),
7039                  bindings = parent.data('$binding') || [];
7040                bindings.push(interpolateFn);
7041                parent.data('$binding', bindings);
7042                if (!hasCompileParent) safeAddClass(parent, 'ng-binding');
7043                scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
7044                  node[0].nodeValue = value;
7045                });
7046              };
7047            }
7048          });
7049        }
7050      }
7051
7052
7053    function getTrustedContext(node, attrNormalizedName) {
7054      if (attrNormalizedName == "srcdoc") {
7055        return $sce.HTML;
7056      }
7057      var tag = nodeName_(node);
7058      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
7059      if (attrNormalizedName == "xlinkHref" ||
7060          (tag == "FORM" && attrNormalizedName == "action") ||
7061          // links can be stylesheets or imports, which can run script in the current origin
7062          (tag == "LINK" && attrNormalizedName == "href") ||
7063          (tag != "IMG" && (attrNormalizedName == "src" ||
7064                            attrNormalizedName == "ngSrc"))) {
7065        return $sce.RESOURCE_URL;
7066      }
7067    }
7068
7069
7070    function addAttrInterpolateDirective(node, directives, value, name) {
7071      var interpolateFn = $interpolate(value, true);
7072
7073      // no interpolation found -> ignore
7074      if (!interpolateFn) return;
7075
7076
7077      if (name === "multiple" && nodeName_(node) === "SELECT") {
7078        throw $compileMinErr("selmulti",
7079            "Binding to the 'multiple' attribute is not supported. Element: {0}",
7080            startingTag(node));
7081      }
7082
7083      directives.push({
7084        priority: 100,
7085        compile: function() {
7086            return {
7087              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
7088                var $$observers = (attr.$$observers || (attr.$$observers = {}));
7089
7090                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
7091                  throw $compileMinErr('nodomevents',
7092                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
7093                          "ng- versions (such as ng-click instead of onclick) instead.");
7094                }
7095
7096                // we need to interpolate again, in case the attribute value has been updated
7097                // (e.g. by another directive's compile function)
7098                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
7099
7100                // if attribute was updated so that there is no interpolation going on we don't want to
7101                // register any observers
7102                if (!interpolateFn) return;
7103
7104                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
7105                // actual attr value
7106                attr[name] = interpolateFn(scope);
7107                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
7108                (attr.$$observers && attr.$$observers[name].$$scope || scope).
7109                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
7110                    //special case for class attribute addition + removal
7111                    //so that class changes can tap into the animation
7112                    //hooks provided by the $animate service. Be sure to
7113                    //skip animations when the first digest occurs (when
7114                    //both the new and the old values are the same) since
7115                    //the CSS classes are the non-interpolated values
7116                    if(name === 'class' && newValue != oldValue) {
7117                      attr.$updateClass(newValue, oldValue);
7118                    } else {
7119                      attr.$set(name, newValue);
7120                    }
7121                  });
7122              }
7123            };
7124          }
7125      });
7126    }
7127
7128
7129    /**
7130     * This is a special jqLite.replaceWith, which can replace items which
7131     * have no parents, provided that the containing jqLite collection is provided.
7132     *
7133     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
7134     *                               in the root of the tree.
7135     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
7136     *                                  the shell, but replace its DOM node reference.
7137     * @param {Node} newNode The new DOM node.
7138     */
7139    function replaceWith($rootElement, elementsToRemove, newNode) {
7140      var firstElementToRemove = elementsToRemove[0],
7141          removeCount = elementsToRemove.length,
7142          parent = firstElementToRemove.parentNode,
7143          i, ii;
7144
7145      if ($rootElement) {
7146        for(i = 0, ii = $rootElement.length; i < ii; i++) {
7147          if ($rootElement[i] == firstElementToRemove) {
7148            $rootElement[i++] = newNode;
7149            for (var j = i, j2 = j + removeCount - 1,
7150                     jj = $rootElement.length;
7151                 j < jj; j++, j2++) {
7152              if (j2 < jj) {
7153                $rootElement[j] = $rootElement[j2];
7154              } else {
7155                delete $rootElement[j];
7156              }
7157            }
7158            $rootElement.length -= removeCount - 1;
7159            break;
7160          }
7161        }
7162      }
7163
7164      if (parent) {
7165        parent.replaceChild(newNode, firstElementToRemove);
7166      }
7167      var fragment = document.createDocumentFragment();
7168      fragment.appendChild(firstElementToRemove);
7169      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
7170      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
7171        var element = elementsToRemove[k];
7172        jqLite(element).remove(); // must do this way to clean up expando
7173        fragment.appendChild(element);
7174        delete elementsToRemove[k];
7175      }
7176
7177      elementsToRemove[0] = newNode;
7178      elementsToRemove.length = 1;
7179    }
7180
7181
7182    function cloneAndAnnotateFn(fn, annotation) {
7183      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
7184    }
7185  }];
7186}
7187
7188var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
7189/**
7190 * Converts all accepted directives format into proper directive name.
7191 * @param name Name to normalize
7192 */
7193function directiveNormalize(name) {
7194  return camelCase(name.replace(PREFIX_REGEXP, ''));
7195}
7196
7197/**
7198 * @ngdoc type
7199 * @name $compile.directive.Attributes
7200 *
7201 * @description
7202 * A shared object between directive compile / linking functions which contains 
7202normalized DOM
7203 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
7204 * needed since all of these are treated as equivalent in Angular:
7205 *
7206 * ```
7207 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7208 * ```
7209 */
7210
7211/**
7212 * @ngdoc property
7213 * @name $compile.directive.Attributes#$attr
7214 *
7215 * @description
7216 * A map of DOM element attribute names to the normalized name. This is
7217 * needed to do reverse lookup from normalized name back to actual name.
7218 */
7219
7220
7221/**
7222 * @ngdoc method
7223 * @name $compile.directive.Attributes#$set
7224 * @kind function
7225 *
7226 * @description
7227 * Set DOM element attribute value.
7228 *
7229 *
7230 * @param {string} name Normalized element attribute name of the property to modify. The name is
7231 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7232 *          property to the original name.
7233 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7234 */
7235
7236
7237
7238/**
7239 * Closure compiler type information
7240 */
7241
7242function nodesetLinkingFn(
7243  /* angular.Scope */ scope,
7244  /* NodeList */ nodeList,
7245  /* Element */ rootElement,
7246  /* function(Function) */ boundTranscludeFn
7247){}
7248
7249function directiveLinkingFn(
7250  /* nodesetLinkingFn */ nodesetLinkingFn,
7251  /* angular.Scope */ scope,
7252  /* Node */ node,
7253  /* Element */ rootElement,
7254  /* function(Function) */ boundTranscludeFn
7255){}
7256
7257function tokenDifference(str1, str2) {
7258  var values = '',
7259      tokens1 = str1.split(/\s+/),
7260      tokens2 = str2.split(/\s+/);
7261
7262  outer:
7263  for(var i = 0; i < tokens1.length; i++) {
7264    var token = tokens1[i];
7265    for(var j = 0; j < tokens2.length; j++) {
7266      if(token == tokens2[j]) continue outer;
7267    }
7268    values += (values.length > 0 ? ' ' : '') + token;
7269  }
7270  return values;
7271}
7272
7273/**
7274 * @ngdoc provider
7275 * @name $controllerProvider
7276 * @description
7277 * The {@link ng.$controller $controller service} is used by Angular to create new
7278 * controllers.
7279 *
7280 * This provider allows controller registration via the
7281 * {@link ng.$controllerProvider#register register} method.
7282 */
7283function $ControllerProvider() {
7284  var controllers = {},
7285      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7286
7287
7288  /**
7289   * @ngdoc method
7290   * @name $controllerProvider#register
7291   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7292   *    the names and the values are the constructors.
7293   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7294   *    annotations in the array notation).
7295   */
7296  this.register = function(name, constructor) {
7297    assertNotHasOwnProperty(name, 'controller');
7298    if (isObject(name)) {
7299      extend(controllers, name);
7300    } else {
7301      controllers[name] = constructor;
7302    }
7303  };
7304
7305
7306  this.$get = ['$injector', '$window', function($injector, $window) {
7307
7308    /**
7309     * @ngdoc service
7310     * @name $controller
7311     * @requires $injector
7312     *
7313     * @param {Function|string} constructor If called with a function then it's considered to be the
7314     *    controller constructor function. Otherwise it's considered to be a string which is used
7315     *    to retrieve the controller constructor using the following steps:
7316     *
7317     *    * check if a controller with given name is registered via `$controllerProvider`
7318     *    * check if evaluating the string on the current scope returns a constructor
7319     *    * check `window[constructor]` on the global `window` object
7320     *
7321     * @param {Object} locals Injection locals for Controller.
7322     * @return {Object} Instance of given controller.
7323     *
7324     * @description
7325     * `$controller` service is responsible for instantiating controllers.
7326     *
7327     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7328     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7329     */
7330    return function(expression, locals) {
7331      var instance, match, constructor, identifier;
7332
7333      if(isString(expression)) {
7334        match = expression.match(CNTRL_REG),
7335        constructor = match[1],
7336        identifier = match[3];
7337        expression = controllers.hasOwnProperty(constructor)
7338            ? controllers[constructor]
7339            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7340
7341        assertArgFn(expression, constructor, true);
7342      }
7343
7344      instance = $injector.instantiate(expression, locals);
7345
7346      if (identifier) {
7347        if (!(locals && typeof locals.$scope === 'object')) {
7348          throw minErr('$controller')('noscp',
7349              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7350              constructor || expression.name, identifier);
7351        }
7352
7353        locals.$scope[identifier] = instance;
7354      }
7355
7356      return instance;
7357    };
7358  }];
7359}
7360
7361/**
7362 * @ngdoc service
7363 * @name $document
7364 * @requires $window
7365 *
7366 * @description
7367 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7368 *
7369 * @example
7370   <example module="documentExample">
7371     <file name="index.html">
7372       <div ng-controller="ExampleController">
7373         <p>$document title: <b ng-bind="title"></b></p>
7374         <p>window.document title: <b ng-bind="windowTitle"></b></p>
7375       </div>
7376     </file>
7377     <file name="script.js">
7378       angular.module('documentExample', [])
7379         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
7380           $scope.title = $document[0].title;
7381           $scope.windowTitle = angular.element(window.document)[0].title;
7382         }]);
7383     </file>
7384   </example>
7385 */
7386function $DocumentProvider(){
7387  this.$get = ['$window', function(window){
7388    return jqLite(window.document);
7389  }];
7390}
7391
7392/**
7393 * @ngdoc service
7394 * @name $exceptionHandler
7395 * @requires ng.$log
7396 *
7397 * @description
7398 * Any uncaught exception in angular expressions is delegated to this service.
7399 * The default implementation simply delegates to `$log.error` which logs it into
7400 * the browser console.
7401 *
7402 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7403 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7404 *
7405 * ## Example:
7406 *
7407 * ```js
7408 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7409 *     return function (exception, cause) {
7410 *       exception.message += ' (caused by "' + cause + '")';
7411 *       throw exception;
7412 *     };
7413 *   });
7414 * ```
7415 *
7416 * This example will override the normal action of `$exceptionHandler`, to make angular
7417 * exceptions fail hard when they happen, instead of just logging to the console.
7418 *
7419 * @param {Error} exception Exception associated with the error.
7420 * @param {string=} cause optional information about the context in which
7421 *       the error was thrown.
7422 *
7423 */
7424function $ExceptionHandlerProvider() {
7425  this.$get = ['$log', function($log) {
7426    return function(exception, cause) {
7427      $log.error.apply($log, arguments);
7428    };
7429  }];
7430}
7431
7432/**
7433 * Parse headers into key value object
7434 *
7435 * @param {string} headers Raw headers as a string
7436 * @returns {Object} Parsed headers as key value object
7437 */
7438function parseHeaders(headers) {
7439  var parsed = {}, key, val, i;
7440
7441  if (!headers) return parsed;
7442
7443  forEach(headers.split('\n'), function(line) {
7444    i = line.indexOf(':');
7445    key = lowercase(trim(line.substr(0, i)));
7446    val = trim(line.substr(i + 1));
7447
7448    if (key) {
7449      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
7450    }
7451  });
7452
7453  return parsed;
7454}
7455
7456
7457/**
7458 * Returns a function that provides access to parsed headers.
7459 *
7460 * Headers are lazy parsed when first requested.
7461 * @see parseHeaders
7462 *
7463 * @param {(string|Object)} headers Headers to provide access to.
7464 * @returns {function(string=)} Returns a getter function which if called with:
7465 *
7466 *   - if called with single an argument returns a single header value or null
7467 *   - if called with no arguments returns an object containing all headers.
7468 */
7469function headersGetter(headers) {
7470  var headersObj = isObject(headers) ? headers : undefined;
7471
7472  return function(name) {
7473    if (!headersObj) headersObj =  parseHeaders(headers);
7474
7475    if (name) {
7476      return headersObj[lowercase(name)] || null;
7477    }
7478
7479    return headersObj;
7480  };
7481}
7482
7483
7484/**
7485 * Chain all given functions
7486 *
7487 * This function is used for both request and response transforming
7488 *
7489 * @param {*} data Data to transform.
7490 * @param {function(string=)} headers Http headers getter fn.
7491 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7492 * @returns {*} Transformed data.
7493 */
7494function transformData(data, headers, fns) {
7495  if (isFunction(fns))
7496    return fns(data, headers);
7497
7498  forEach(fns, function(fn) {
7499    data = fn(data, headers);
7500  });
7501
7502  return data;
7503}
7504
7505
7506function isSuccess(status) {
7507  return 200 <= status && status < 300;
7508}
7509
7510
7511/**
7512 * @ngdoc provider
7513 * @name $httpProvider
7514 * @description
7515 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
7516 * */
7517function $HttpProvider() {
7518  var JSON_START = /^\s*(\[|\{[^\{])/,
7519      JSON_END = /[\}\]]\s*$/,
7520      PROTECTION_PREFIX = /^\)\]\}',?\n/,
7521      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7522
7523  /**
7524   * @ngdoc property
7525   * @name $httpProvider#defaults
7526   * @description
7527   *
7528   * Object containing default values for all {@link ng.$http $http} requests.
7529   *
7530   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
7531   * Defaults value is `'XSRF-TOKEN'`.
7532   *
7533   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
7534   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
7535   *
7536   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
7537   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
7538   * setting default headers.
7539   *     - **`defaults.headers.common`**
7540   *     - **`defaults.headers.post`**
7541   *     - **`defaults.headers.put`**
7542   *     - **`defaults.headers.patch`**
7543   **/
7544  var defaults = this.defaults = {
7545    // transform incoming response data
7546    transformResponse: [function(data) {
7547      if (isString(data)) {
7548        // strip json vulnerability protection prefix
7549        data = data.replace(PROTECTION_PREFIX, '');
7550        if (JSON_START.test(data) && JSON_END.test(data))
7551          data = fromJson(data);
7552      }
7553      return data;
7554    }],
7555
7556    // transform outgoing request data
7557    transformRequest: [function(d) {
7558      return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7559    }],
7560
7561    // default headers
7562    headers: {
7563      common: {
7564        'Accept': 'application/json, text/plain, */*'
7565      },
7566      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7567      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
7568      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
7569    },
7570
7571    xsrfCookieName: 'XSRF-TOKEN',
7572    xsrfHeaderName: 'X-XSRF-TOKEN'
7573  };
7574
7575  /**
7576   * @ngdoc property
7577   * @name $httpProvider#interceptors
7578   * @description
7579   *
7580   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
7581   * pre-processing of request or postprocessing of responses.
7582   *
7583   * These service factories are ordered by request, i.e. they are applied in the same order as the
7584   * array, on request, but reverse order, on response.
7585   *
7586   * {@link ng.$http#interceptors Interceptors detailed info}
7587   **/
7588  var interceptorFactories = this.interceptors = [];
7589
7590  /**
7591   * For historical reasons, response interceptors are ordered by the order in which
7592   * they are applied to the response. (This is the opposite of interceptorFactories)
7593   */
7594  var responseInterceptorFactories = this.responseInterceptors = [];
7595
7596  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7597      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7598
7599    var defaultCache = $cacheFactory('$http');
7600
7601    /**
7602     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7603     * The reversal is needed so that we can build up the interception chain around the
7604     * server request.
7605     */
7606    var reversedInterceptors = [];
7607
7608    forEach(interceptorFactories, function(interceptorFactory) {
7609      reversedInterceptors.unshift(isString(interceptorFactory)
7610          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7611    });
7612
7613    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7614      var responseFn = isString(interceptorFactory)
7615          ? $injector.get(interceptorFactory)
7616          : $injector.invoke(interceptorFactory);
7617
7618      /**
7619       * Response interceptors go before "around" interceptors (no real reason, just
7620       * had to pick one.) But they are already reversed, so we can't use unshift, hence
7621       * the splice.
7622       */
7623      reversedInterceptors.splice(index, 0, {
7624        response: function(response) {
7625          return responseFn($q.when(response));
7626        },
7627        responseError: function(response) {
7628          return responseFn($q.reject(response));
7629        }
7630      });
7631    });
7632
7633
7634    /**
7635     * @ngdoc service
7636     * @kind function
7637     * @name $http
7638     * @requires ng.$httpBackend
7639     * @requires $cacheFactory
7640     * @requires $rootScope
7641     * @requires $q
7642     * @requires $injector
7643     *
7644     * @description
7645     * The `$http` service is a core Angular service that facilitates communication with the remote
7646     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7647     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7648     *
7649     * For unit testing applications that use `$http` service, see
7650     * {@link ngMock.$httpBackend $httpBackend mock}.
7651     *
7652     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7653     * $resource} service.
7654     *
7655     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7656     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7657     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7658     *
7659     *
7660     * # General usage
7661     * The `$http` service is a function which takes a single argument — a configuration object —
7662     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7663     * with two $http specific methods: `success` and `error`.
7664     *
7665     * ```js
7666     *   $http({method: 'GET', url: '/someUrl'}).
7667     *     success(function(data, status, headers, config) {
7668     *       // this callback will be called asynchronously
7669     *       // when the response is available
7670     *     }).
7671     *     error(function(data, status, headers, config) {
7672     *       // called asynchronously if an error occurs
7673     *       // or server returns response with an error status.
7674     *     });
7675     * ```
7676     *
7677     * Since the returned value of calling the $http function is a `promise`, you can also use
7678     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7679     * an object representing the response. See the API signature and type info below for more
7680     * details.
7681     *
7682     * A response status code between 200 and 299 is considered a success status and
7683     * will result in the success callback being called. Note that if the response is a redirect,
7684     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7685     * called for such responses.
7686     *
7687     * # Writing Unit Tests that use $http
7688     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7689     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7690     * request using trained responses.
7691     *
7692     * ```
7693     * $httpBackend.expectGET(...);
7694     * $http.get(...);
7695     * $httpBackend.flush();
7696     * ```
7697     *
7698     * # Shortcut methods
7699     *
7700     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7701     * request data must be passed in for POST/PUT requests.
7702     *
7703     * ```js
7704     *   $http.get('/someUrl').success(successCallback);
7705     *   $http.post('/someUrl', data).success(successCallback);
7706     * ```
7707     *
7708     * Complete list of shortcut methods:
7709     *
7710     * - {@link ng.$http#get $http.get}
7711     * - {@link ng.$http#head $http.head}
7712     * - {@link ng.$http#post $http.post}
7713     * - {@link ng.$http#put $http.put}
7714     * - {@link ng.$http#delete $http.delete}
7715     * - {@link ng.$http#jsonp $http.jsonp}
7716     * - {@link ng.$http#patch $http.patch}
7717     *
7718     *
7719     * # Setting HTTP Headers
7720     *
7721     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7722     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7723     * object, which currently contains this default configuration:
7724     *
7725     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7726     *   - `Accept: application/json, text/plain, * / *`
7727     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7728     *   - `Content-Type: application/json`
7729     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7730     *   - `Content-Type: application/json`
7731     *
7732     * To add or overwrite these defaults, simply add or remove a property from these configuration
7733     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7734     * with the lowercased HTTP method name as the key, e.g.
7735     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7736     *
7737     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7738     * fashion. For example:
7739     *
7740     * ```
7741     * module.run(function($http) {
7742     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7743     * });
7744     * ```
7745     *
7746     * In addition, you can supply a `headers` property in the config object passed when
7747     * calling `$http(config)`, which overrides the defaults without changing them globally.
7748     *
7749     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
7750     * Use the `headers` property, setting the desired header to `undefined`. For example:
7751     *
7752     * ```js
7753     * var req = {
7754     *  method: 'POST',
7755     *  url: 'http://example.com',
7756     *  headers: {
7757     *    'Content-Type': undefined
7758     *  },
7759     *  data: { test: 'test' },
7760     * }
7761     *
7762     * $http(req).success(function(){...}).error(function(){...});
7763     * ```
7764     *
7765     * # Transforming Requests and Responses
7766     *
7767     * Both requests and responses can be transformed using transform functions. By default, Angular
7768     * applies these transformations:
7769     *
7770     * Request transformations:
7771     *
7772     * - If the `data` property of the request configuration object contains an object, serialize it
7773     *   into JSON format.
7774     *
7775     * Response transformations:
7776     *
7777     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7778     *  - If JSON response is detected, deserialize it using a JSON parser.
7779     *
7780     * To globally augment or override the default transforms, modify the
7781     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7782     * properties. These properties are by default an array of transform functions, which allows you
7783     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7784     * also decide to completely override any default transformations by assigning your
7785     * transformation functions to these properties directly without the array wrapper.  These defaults
7786     * are again available on the $http factory at run-time, which may be useful if you have run-time
7787     * services you wish to be involved in your transformations.
7788     *
7789     * Similarly, to locally override the request/response transforms, augment the
7790     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7791     * into `$http`.
7792     *
7793     *
7794     * # Caching
7795     *
7796     * To enable caching, set the request configuration `cache` property to `true` (to use default
7797     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7798     * When the cache is enabled, `$http` stores the response from the server in the specified
7799     * cache. The next time the same request is made, the response is served from the cache without
7800     * sending a request to the server.
7801     *
7802     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7803     * the same way that real requests are.
7804     *
7805     * If there are multiple GET requests for the same URL that should be cached using the same
7806     * cache, but the cache is not populated yet, only one request to the server will be made and
7807     * the remaining requests will be fulfilled using the response from the first request.
7808     *
7809     * You can change the default cache to a new object (built with
7810     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7811     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7812     * their `cache` property to `true` will now use this cache object.
7813     *
7814     * If you set the default cache to `false` then only requests that specify their own custom
7815     * cache object will be cached.
7816     *
7817     * # Interceptors
7818     *
7819     * Before you start creating interceptors, be sure to understand the
7820     * {@link ng.$q $q and deferred/promise APIs}.
7821     *
7822     * For purposes of global error handling, authentication, or any kind of synchronous or
7823     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7824     * able to intercept requests before they are handed to the server and
7825     * responses before they are handed over to the application code that
7826     * initiated these requests. The interceptors leverage the {@link ng.$q
7827     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7828     *
7829     * The interceptors are service factories that are registered with the `$httpProvider` by
7830     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7831     * injected with dependencies (if specified) and returns the interceptor.
7832     *
7833     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7834     *
7835     *   * `request`: interceptors get called with a http `config` object. The function is free to
7836     *     modify the `config` object or create a new one. The function needs to return the `config`
7837     *     object directly, or a promise containing the `config` or a new `config` object.
7838     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7839     *     resolved with a rejection.
7840     *   * `response`: interceptors get called with http `response` object. The function is free to
7841     *     modify the `response` object or create a new one. The function needs to return the `response`
7842     *     object directly, or as a promise containing the `response` or a new `response` object.
7843     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7844     *     resolved with a rejection.
7845     *
7846     *
7847     * ```js
7848     *   // register the interceptor as a service
7849     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7850     *     return {
7851     *       // optional method
7852     *       'request': function(config) {
7853     *         // do something on success
7854     *         return config;
7855     *       },
7856     *
7857     *       // optional method
7858     *      'requestError': function(rejection) {
7859     *         // do something on error
7860     *         if (canRecover(rejection)) {
7861     *           return responseOrNewPromise
7862     *         }
7863     *         return $q.reject(rejection);
7864     *       },
7865     *
7866     *
7867     *
7868     *       // optional method
7869     *       'response': function(response) {
7870     *         // do something on success
7871     *         return response;
7872     *       },
7873     *
7874     *       // optional method
7875     *      'responseError': function(rejection) {
7876     *         // do something on error
7877     *         if (canRecover(rejection)) {
7878     *           return responseOrNewPromise
7879     *         }
7880     *         return $q.reject(rejection);
7881     *       }
7882     *     };
7883     *   });
7884     *
7885     *   $httpProvider.interceptors.push('myHttpInterceptor');
7886     *
7887     *
7888     *   // alternatively, register the interceptor via an anonymous factory
7889     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7890     *     return {
7891     *      'request': function(config) {
7892     *          // same as above
7893     *       },
7894     *
7895     *       'response': function(response) {
7896     *          // same as above
7897     *       }
7898     *     };
7899     *   });
7900     * ```
7901     *
7902     * # Response interceptors (DEPRECATED)
7903     *
7904     * Before you start creating interceptors, be sure to understand the
7905     * {@link ng.$q $q and deferred/promise APIs}.
7906     *
7907     * For purposes of global error handling, authentication or any kind of synchronous or
7908     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7909     * responses for http requests before they are handed over to the application code that
7910     * initiated these requests. The response interceptors leverage the {@link ng.$q
7911     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7912     *
7913     * The interceptors are service factories that are registered with the $httpProvider by
7914     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7915     * injected with dependencies (if specified) and returns the interceptor  — a function that
7916     * takes a {@link ng.$q promise} and returns the original or a new promise.
7917     *
7918     * ```js
7919     *   // register the interceptor as a service
7920     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7921     *     return function(promise) {
7922     *       return promise.then(function(response) {
7923     *         // do something on success
7924     *         return response;
7925     *       }, function(response) {
7926     *         // do something on error
7927     *         if (canRecover(response)) {
7928     *           return responseOrNewPromise
7929     *         }
7930     *         return $q.reject(response);
7931     *       });
7932     *     }
7933     *   });
7934     *
7935     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7936     *
7937     *
7938     *   // register the interceptor via an anonymous factory
7939     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7940     *     return function(promise) {
7941     *       // same as above
7942     *     }
7943     *   });
7944     * ```
7945     *
7946     *
7947     * # Security Considerations
7948     *
7949     * When designing web applications, consider security threats from:
7950     *
7951     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7952     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7953     *
7954     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7955     * pre-configured with strategies that address these issues, but for this to work backend server
7956     * cooperation is required.
7957     *
7958     * ## JSON Vulnerability Protection
7959     *
7960     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7961     * allows third party website to turn your JSON resource URL into
7962     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7963     * counter this your server can prefix all JSON requests with following str
7963ing `")]}',\n"`.
7964     * Angular will automatically strip the prefix before processing it as JSON.
7965     *
7966     * For example if your server needs to return:
7967     * ```js
7968     * ['one','two']
7969     * ```
7970     *
7971     * which is vulnerable to attack, your server can return:
7972     * ```js
7973     * )]}',
7974     * ['one','two']
7975     * ```
7976     *
7977     * Angular will strip the prefix, before processing the JSON.
7978     *
7979     *
7980     * ## Cross Site Request Forgery (XSRF) Protection
7981     *
7982     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7983     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7984     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7985     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7986     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7987     * the XHR came from JavaScript running on your domain. The header will not be set for
7988     * cross-domain requests.
7989     *
7990     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7991     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7992     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7993     * that only JavaScript running on your domain could have sent the request. The token must be
7994     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7995     * making up its own tokens). We recommend that the token is a digest of your site's
7996     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
7997     * for added security.
7998     *
7999     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
8000     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
8001     * or the per-request config object.
8002     *
8003     *
8004     * @param {object} config Object describing the request to be made and how it should be
8005     *    processed. The object has following properties:
8006     *
8007     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
8008     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
8009     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
8010     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
8011     *      JSONified.
8012     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
8013     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
8014     *      HTTP headers to send to the server. If the return value of a function is null, the
8015     *      header will not be sent.
8016     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
8017     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
8018     *    - **transformRequest** –
8019     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
8020     *      transform function or an array of such functions. The transform function takes the http
8021     *      request body and headers and returns its transformed (typically serialized) version.
8022     *    - **transformResponse** –
8023     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
8024     *      transform function or an array of such functions. The transform function takes the http
8025     *      response body and headers and returns its transformed (typically deserialized) version.
8026     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
8027     *      GET request, otherwise if a cache instance built with
8028     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
8029     *      caching.
8030     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
8031     *      that should abort the request when resolved.
8032     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
8033     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
8034     *      for more information.
8035     *    - **responseType** - `{string}` - see
8036     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
8037     *
8038     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
8039     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
8040     *   method takes two arguments a success and an error callback which will be called with a
8041     *   response object. The `success` and `error` methods take a single argument - a function that
8042     *   will be called when the request succeeds or fails respectively. The arguments passed into
8043     *   these functions are destructured representation of the response object passed into the
8044     *   `then` method. The response object has these properties:
8045     *
8046     *   - **data** – `{string|Object}` – The response body transformed with the transform
8047     *     functions.
8048     *   - **status** – `{number}` – HTTP status code of the response.
8049     *   - **headers** – `{function([headerName])}` – Header getter function.
8050     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
8051     *   - **statusText** – `{string}` – HTTP status text of the response.
8052     *
8053     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
8054     *   requests. This is primarily meant to be used for debugging purposes.
8055     *
8056     *
8057     * @example
8058<example module="httpExample">
8059<file name="index.html">
8060  <div ng-controller="FetchController">
8061    <select ng-model="method">
8062      <option>GET</option>
8063      <option>JSONP</option>
8064    </select>
8065    <input type="text" ng-model="url" size="80"/>
8066    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
8067    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
8068    <button id="samplejsonpbtn"
8069      ng-click="updateModel('JSONP',
8070                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
8071      Sample JSONP
8072    </button>
8073    <button id="invalidjsonpbtn"
8074      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
8075        Invalid JSONP
8076      </button>
8077    <pre>http status code: {{status}}</pre>
8078    <pre>http response data: {{data}}</pre>
8079  </div>
8080</file>
8081<file name="script.js">
8082  angular.module('httpExample', [])
8083    .controller('FetchController', ['$scope', '$http', '$templateCache',
8084      function($scope, $http, $templateCache) {
8085        $scope.method = 'GET';
8086        $scope.url = 'http-hello.html';
8087
8088        $scope.fetch = function() {
8089          $scope.code = null;
8090          $scope.response = null;
8091
8092          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
8093            success(function(data, status) {
8094              $scope.status = status;
8095              $scope.data = data;
8096            }).
8097            error(function(data, status) {
8098              $scope.data = data || "Request failed";
8099              $scope.status = status;
8100          });
8101        };
8102
8103        $scope.updateModel = function(method, url) {
8104          $scope.method = method;
8105          $scope.url = url;
8106        };
8107      }]);
8108</file>
8109<file name="http-hello.html">
8110  Hello, $http!
8111</file>
8112<file name="protractor.js" type="protractor">
8113  var status = element(by.binding('status'));
8114  var data = element(by.binding('data'));
8115  var fetchBtn = element(by.id('fetchbtn'));
8116  var sampleGetBtn = element(by.id('samplegetbtn'));
8117  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
8118  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
8119
8120  it('should make an xhr GET request', function() {
8121    sampleGetBtn.click();
8122    fetchBtn.click();
8123    expect(status.getText()).toMatch('200');
8124    expect(data.getText()).toMatch(/Hello, \$http!/);
8125  });
8126
8127// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
8128// it('should make a JSONP request to angularjs.org', function() {
8129//   sampleJsonpBtn.click();
8130//   fetchBtn.click();
8131//   expect(status.getText()).toMatch('200');
8132//   expect(data.getText()).toMatch(/Super Hero!/);
8133// });
8134
8135  it('should make JSONP request to invalid URL and invoke the error handler',
8136      function() {
8137    invalidJsonpBtn.click();
8138    fetchBtn.click();
8139    expect(status.getText()).toMatch('0');
8140    expect(data.getText()).toMatch('Request failed');
8141  });
8142</file>
8143</example>
8144     */
8145    function $http(requestConfig) {
8146      var config = {
8147        method: 'get',
8148        transformRequest: defaults.transformRequest,
8149        transformResponse: defaults.transformResponse
8150      };
8151      var headers = mergeHeaders(requestConfig);
8152
8153      extend(config, requestConfig);
8154      config.headers = headers;
8155      config.method = uppercase(config.method);
8156
8157      var serverRequest = function(config) {
8158        headers = config.headers;
8159        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
8160
8161        // strip content-type if data is undefined
8162        if (isUndefined(reqData)) {
8163          forEach(headers, function(value, header) {
8164            if (lowercase(header) === 'content-type') {
8165                delete headers[header];
8166            }
8167          });
8168        }
8169
8170        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
8171          config.withCredentials = defaults.withCredentials;
8172        }
8173
8174        // send request
8175        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
8176      };
8177
8178      var chain = [serverRequest, undefined];
8179      var promise = $q.when(config);
8180
8181      // apply interceptors
8182      forEach(reversedInterceptors, function(interceptor) {
8183        if (interceptor.request || interceptor.requestError) {
8184          chain.unshift(interceptor.request, interceptor.requestError);
8185        }
8186        if (interceptor.response || interceptor.responseError) {
8187          chain.push(interceptor.response, interceptor.responseError);
8188        }
8189      });
8190
8191      while(chain.length) {
8192        var thenFn = chain.shift();
8193        var rejectFn = chain.shift();
8194
8195        promise = promise.then(thenFn, rejectFn);
8196      }
8197
8198      promise.success = function(fn) {
8199        promise.then(function(response) {
8200          fn(response.data, response.status, response.headers, config);
8201        });
8202        return promise;
8203      };
8204
8205      promise.error = function(fn) {
8206        promise.then(null, function(response) {
8207          fn(response.data, response.status, response.headers, config);
8208        });
8209        return promise;
8210      };
8211
8212      return promise;
8213
8214      function transformResponse(response) {
8215        // make a copy since the response must be cacheable
8216        var resp = extend({}, response, {
8217          data: transformData(response.data, response.headers, config.transformResponse)
8218        });
8219        return (isSuccess(response.status))
8220          ? resp
8221          : $q.reject(resp);
8222      }
8223
8224      function mergeHeaders(config) {
8225        var defHeaders = defaults.headers,
8226            reqHeaders = extend({}, config.headers),
8227            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
8228
8229        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
8230
8231        // using for-in instead of forEach to avoid unecessary iteration after header has been found
8232        defaultHeadersIteration:
8233        for (defHeaderName in defHeaders) {
8234          lowercaseDefHeaderName = lowercase(defHeaderName);
8235
8236          for (reqHeaderName in reqHeaders) {
8237            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
8238              continue defaultHeadersIteration;
8239            }
8240          }
8241
8242          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
8243        }
8244
8245        // execute if header value is a function for merged headers
8246        execHeaders(reqHeaders);
8247        return reqHeaders;
8248
8249        function execHeaders(headers) {
8250          var headerContent;
8251
8252          forEach(headers, function(headerFn, header) {
8253            if (isFunction(headerFn)) {
8254              headerContent = headerFn();
8255              if (headerContent != null) {
8256                headers[header] = headerContent;
8257              } else {
8258                delete headers[header];
8259              }
8260            }
8261          });
8262        }
8263      }
8264    }
8265
8266    $http.pendingRequests = [];
8267
8268    /**
8269     * @ngdoc method
8270     * @name $http#get
8271     *
8272     * @description
8273     * Shortcut method to perform `GET` request.
8274     *
8275     * @param {string} url Relative or absolute URL specifying the destination of the request
8276     * @param {Object=} config Optional configuration object
8277     * @returns {HttpPromise} Future object
8278     */
8279
8280    /**
8281     * @ngdoc method
8282     * @name $http#delete
8283     *
8284     * @description
8285     * Shortcut method to perform `DELETE` request.
8286     *
8287     * @param {string} url Relative or absolute URL specifying the destination of the request
8288     * @param {Object=} config Optional configuration object
8289     * @returns {HttpPromise} Future object
8290     */
8291
8292    /**
8293     * @ngdoc method
8294     * @name $http#head
8295     *
8296     * @description
8297     * Shortcut method to perform `HEAD` request.
8298     *
8299     * @param {string} url Relative or absolute URL specifying the destination of the request
8300     * @param {Object=} config Optional configuration object
8301     * @returns {HttpPromise} Future object
8302     */
8303
8304    /**
8305     * @ngdoc method
8306     * @name $http#jsonp
8307     *
8308     * @description
8309     * Shortcut method to perform `JSONP` request.
8310     *
8311     * @param {string} url Relative or absolute URL specifying the destination of the request.
8312     *                     The name of the callback should be the string `JSON_CALLBACK`.
8313     * @param {Object=} config Optional configuration object
8314     * @returns {HttpPromise} Future object
8315     */
8316    createShortMethods('get', 'delete', 'head', 'jsonp');
8317
8318    /**
8319     * @ngdoc method
8320     * @name $http#post
8321     *
8322     * @description
8323     * Shortcut method to perform `POST` request.
8324     *
8325     * @param {string} url Relative or absolute URL specifying the destination of the request
8326     * @param {*} data Request content
8327     * @param {Object=} config Optional configuration object
8328     * @returns {HttpPromise} Future object
8329     */
8330
8331    /**
8332     * @ngdoc method
8333     * @name $http#put
8334     *
8335     * @description
8336     * Shortcut method to perform `PUT` request.
8337     *
8338     * @param {string} url Relative or absolute URL specifying the destination of the request
8339     * @param {*} data Request content
8340     * @param {Object=} config Optional configuration object
8341     * @returns {HttpPromise} Future object
8342     */
8343
8344    /**
8345     * @ngdoc method
8346     * @name $http#patch
8347     *
8348     * @description
8349     * Shortcut method to perform `PATCH` request.
8350     *
8351     * @param {string} url Relative or absolute URL specifying the destination of the request
8352     * @param {*} data Request content
8353     * @param {Object=} config Optional configuration object
8354     * @returns {HttpPromise} Future object
8355     */
8356    createShortMethodsWithData('post', 'put', 'patch');
8357
8358    /**
8359     * @ngdoc property
8360     * @name $http#defaults
8361     *
8362     * @description
8363     * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8364     * default headers, withCredentials as well as request and response transformations.
8365     *
8366     * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8367     */
8368    $http.defaults = defaults;
8369
8370
8371    return $http;
8372
8373
8374    function createShortMethods(names) {
8375      forEach(arguments, function(name) {
8376        $http[name] = function(url, config) {
8377          return $http(extend(config || {}, {
8378            method: name,
8379            url: url
8380          }));
8381        };
8382      });
8383    }
8384
8385
8386    function createShortMethodsWithData(name) {
8387      forEach(arguments, function(name) {
8388        $http[name] = function(url, data, config) {
8389          return $http(extend(config || {}, {
8390            method: name,
8391            url: url,
8392            data: data
8393          }));
8394        };
8395      });
8396    }
8397
8398
8399    /**
8400     * Makes the request.
8401     *
8402     * !!! ACCESSES CLOSURE VARS:
8403     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8404     */
8405    function sendReq(config, reqData, reqHeaders) {
8406      var deferred = $q.defer(),
8407          promise = deferred.promise,
8408          cache,
8409          cachedResp,
8410          url = buildUrl(config.url, config.params);
8411
8412      $http.pendingRequests.push(config);
8413      promise.then(removePendingReq, removePendingReq);
8414
8415
8416      if ((config.cache || defaults.cache) && config.cache !== false &&
8417          (config.method === 'GET' || config.method === 'JSONP')) {
8418        cache = isObject(config.cache) ? config.cache
8419              : isObject(defaults.cache) ? defaults.cache
8420              : defaultCache;
8421      }
8422
8423      if (cache) {
8424        cachedResp = cache.get(url);
8425        if (isDefined(cachedResp)) {
8426          if (isPromiseLike(cachedResp)) {
8427            // cached request has already been sent, but there is no response yet
8428            cachedResp.then(removePendingReq, removePendingReq);
8429            return cachedResp;
8430          } else {
8431            // serving from cache
8432            if (isArray(cachedResp)) {
8433              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
8434            } else {
8435              resolvePromise(cachedResp, 200, {}, 'OK');
8436            }
8437          }
8438        } else {
8439          // put the promise for the non-transformed response into cache as a placeholder
8440          cache.put(url, promise);
8441        }
8442      }
8443
8444
8445      // if we won't have the response in cache, set the xsrf headers and
8446      // send the request to the backend
8447      if (isUndefined(cachedResp)) {
8448        var xsrfValue = urlIsSameOrigin(config.url)
8449            ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
8450            : undefined;
8451        if (xsrfValue) {
8452          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
8453        }
8454
8455        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8456            config.withCredentials, config.responseType);
8457      }
8458
8459      return promise;
8460
8461
8462      /**
8463       * Callback registered to $httpBackend():
8464       *  - caches the response if desired
8465       *  - resolves the raw $http promise
8466       *  - calls $apply
8467       */
8468      function done(status, response, headersString, statusText) {
8469        if (cache) {
8470          if (isSuccess(status)) {
8471            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8472          } else {
8473            // remove promise from the cache
8474            cache.remove(url);
8475          }
8476        }
8477
8478        resolvePromise(response, status, headersString, statusText);
8479        if (!$rootScope.$$phase) $rootScope.$apply();
8480      }
8481
8482
8483      /**
8484       * Resolves the raw $http promise.
8485       */
8486      function resolvePromise(response, status, headers, statusText) {
8487        // normalize internal statuses to 0
8488        status = Math.max(status, 0);
8489
8490        (isSuccess(status) ? deferred.resolve : deferred.reject)({
8491          data: response,
8492          status: status,
8493          headers: headersGetter(headers),
8494          config: config,
8495          statusText : statusText
8496        });
8497      }
8498
8499
8500      function removePendingReq() {
8501        var idx = indexOf($http.pendingRequests, config);
8502        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8503      }
8504    }
8505
8506
8507    function buildUrl(url, params) {
8508      if (!params) return url;
8509      var parts = [];
8510      forEachSorted(params, function(value, key) {
8511        if (value === null || isUndefined(value)) return;
8512        if (!isArray(value)) value = [value];
8513
8514        forEach(value, function(v) {
8515          if (isObject(v)) {
8516            if (isDate(v)){
8517              v = v.toISOString();
8518            } else {
8519              v = toJson(v);
8520            }
8521          }
8522          parts.push(encodeUriQuery(key) + '=' +
8523                     encodeUriQuery(v));
8524        });
8525      });
8526      if(parts.length > 0) {
8527        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8528      }
8529      return url;
8530    }
8531  }];
8532}
8533
8534function createXhr(method) {
8535    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8536    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8537    //if it is available
8538    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
8539      !window.XMLHttpRequest)) {
8540      return new window.ActiveXObject("Microsoft.XMLHTTP");
8541    } else if (window.XMLHttpRequest) {
8542      return new window.XMLHttpRequest();
8543    }
8544
8545    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8546}
8547
8548/**
8549 * @ngdoc service
8550 * @name $httpBackend
8551 * @requires $window
8552 * @requires $document
8553 *
8554 * @description
8555 * HTTP backend used by the {@link ng.$http service} that delegates to
8556 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8557 *
8558 * You should never need to use this service directly, instead use the higher-level abstractions:
8559 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8560 *
8561 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8562 * $httpBackend} which can be trained with responses.
8563 */
8564function $HttpBackendProvider() {
8565  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
8566    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8567  }];
8568}
8569
8570function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8571  var ABORTED = -1;
8572
8573  // TODO(vojta): fix the signature
8574  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8575    var status;
8576    $browser.$$incOutstandingRequestCount();
8577    url = url || $browser.url();
8578
8579    if (lowercase(method) == 'jsonp') {
8580      var callbackId = '_' + (callbacks.counter++).toString(36);
8581      callbacks[callbackId] = function(data) {
8582        callbacks[callbackId].data = data;
8583        callbacks[callbackId].called = true;
8584      };
8585
8586      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8587          callbackId, function(status, text) {
8588        completeRequest(callback, status, callbacks[callbackId].data, "", text);
8589        callbacks[callbackId] = noop;
8590      });
8591    } else {
8592
8593      var xhr = createXhr(method);
8594
8595      xhr.open(method, url, true);
8596      forEach(headers, function(value, key) {
8597        if (isDefined(value)) {
8598            xhr.setRequestHeader(key, value);
8599        }
8600      });
8601
8602      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8603      // response is in the cache. the promise api will ensure that to the app code the api is
8604      // always async
8605      xhr.onreadystatechange = function() {
8606        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8607        // xhrs that are resolved while the app is in the background (see #5426).
8608        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8609        // continuing
8610        //
8611        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8612        // Safari respectively.
8613        if (xhr && xhr.readyState == 4) {
8614          var responseHeaders = null,
8615              response = null,
8616              statusText = '';
8617
8618          if(status !== ABORTED) {
8619            responseHeaders = xhr.getAllResponseHeaders();
8620
8621            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
8622            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8623            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8624          }
8625
8626          // Accessing statusText on an aborted xhr object will
8627          // throw an 'c00c023f error' in IE9 and lower, don't touch it.
8628          if (!(status === ABORTED && msie < 10)) {
8629            statusText = xhr.statusText;
8630          }
8631
8632          completeRequest(callback,
8633              status || xhr.status,
8634              response,
8635              responseHeaders,
8636              statusText);
8637        }
8638      };
8639
8640      if (withCredentials) {
8641        xhr.withCredentials = true;
8642      }
8643
8644      if (responseType) {
8645        try {
8646          xhr.responseType = responseType;
8647        } catch (e) {
8648          // WebKit added support for the json responseType value on 09/03/2013
8649          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8650          // known to throw when setting the value "json" as the response type. Other older
8651          // browsers implementing the responseType
8652          //
8653          // The json response type can be ignored if not supported, because JSON payloads are
8654          // parsed on the client-side regardless.
8655          if (responseType !== 'json') {
8656            throw e;
8657          }
8658        }
8659      }
8660
8661      xhr.send(post || null);
8662    }
8663
8664    if (timeout > 0) {
8665      var timeoutId = $browserDefer(timeoutRequest, timeout);
8666    } else if (isPromiseLike(timeout)) {
8667      timeout.then(timeoutRequest);
8668    }
8669
8670
8671    function timeoutRequest() {
8672      status = ABORTED;
8673      jsonpDone && jsonpDone();
8674      xhr && xhr.abort();
8675    }
8676
8677    function completeRequest(callback, status, response, headersString, statusText) {
8678      // cancel timeout and subsequent timeout promise resolution
8679      timeoutId && $browserDefer.cancel(timeoutId);
8680      jsonpDone = xhr = null;
8681
8682      // fix status code when it is 0 (0 status is undocumented).
8683      // Occurs when accessing file resources or on Android 4.1 stock browser
8684      // while retrieving files from application cache.
8685      if (status === 0) {
8686        status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8687      }
8688
8689      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8690      status = status === 1223 ? 204 : status;
8691      statusText = statusText || '';
8692
8693      callback(status, response, headersString, statusText);
8694      $browser.$$completeOutstandingRequest(noop);
8695    }
8696  };
8697
8698  function jsonpReq(url, callbackId, done) {
8699    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8700    // - fetches local scripts via XHR and evals them
8701    // - adds and immediately removes script elements from the document
8702    var script = rawDocument.createElement('script'), callback = null;
8703    script.type = "text/javascript";
8704    script.src = url;
8705    script.async = true;
8706
8707    callback = function(event) {
8708      removeEventListenerFn(script, "load", callback);
8709      removeEventListenerFn(script, "error", callback);
8710      rawDocument.body.removeChild(script);
8711      script = null;
8712      var status = -1;
8713      var text = "unknown";
8714
8715      if (event) {
8716        if (event.type === "load" && !callbacks[callbackId].called) {
8717          event = { type: "error" };
8718        }
8719        text = event.type;
8720        status = event.type === "error" ? 404 : 200;
8721      }
8722
8723      if (done) {
8724        done(status, text);
8725      }
8726    };
8727
8728    addEventListenerFn(script, "load", callback);
8729    addEventListenerFn(script, "error", callback);
8730
8731    if (msie <= 8) {
8732      script.onreadystatechange = function() {
8733        if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) {
8734          script.onreadystatechange = null;
8735          callback({
8736            type: 'load'
8737          });
8738        }
8739      };
8740    }
8741
8742    rawDocument.body.appendChild(script);
8743    return callback;
8744  }
8745}
8746
8747var $interpolateMinErr = minErr('$interpolate');
8748
8749/**
8750 * @ngdoc provider
8751 * @name $interpolateProvider
8752 * @kind function
8753 *
8754 * @description
8755 *
8756 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8757 *
8758 * @example
8759<example module="customInterpolationApp">
8760<file name="index.html">
8761<script>
8762  var customInterpolationApp = angular.module('customInterpolationApp', []);
8763
8764  customInterpolationApp.config(function($interpolateProvider) {
8765    $interpolateProvider.startSymbol('//');
8766    $interpolateProvider.endSymbol('//');
8767  });
8768
8769
8770  customInterpolationApp.controller('DemoController', function() {
8771      this.label = "This binding is brought you by // interpolation symbols.";
8772  });
8773</script>
8774<div ng-app="App" ng-controller="DemoController as demo">
8775    //demo.label//
8776</div>
8777</file>
8778<file name="protractor.js" type="protractor">
8779  it('should interpolate binding with custom symbols', function() {
8780    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8781  });
8782</file>
8783</example>
8784 */
8785function $InterpolateProvider() {
8786  var startSymbol = '{{';
8787  var endSymbol = '}}';
8788
8789  /**
8790   * @ngdoc method
8791   * @name $interpolateProvider#startSymbol
8792   * @description
8793   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8794   *
8795   * @param {string=} value new value to set the starting symbol to.
8796   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8797   */
8798  this.startSymbol = function(value){
8799    if (value) {
8800      startSymbol = value;
8801      return this;
8802    } else {
8803      return startSymbol;
8804    }
8805  };
8806
8807  /**
8808   * @ngdoc method
8809   * @name $interpolateProvider#endSymbol
8810   * @description
8811   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8812   *
8813   * @param {string=} value new value to set the ending symbol to.
8814   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8815   */
8816  this.endSymbol = function(value){
8817    if (value) {
8818      endSymbol = value;
8819      return this;
8820    } else {
8821      return endSymbol;
8822    }
8823  };
8824
8825
8826  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8827    var startSymbolLength = startSymbol.length,
8828        endSymbolLength = endSymbol.length;
8829
8830    /**
8831     * @ngdoc service
8832     * @name $interpolate
8833     * @kind function
8834     *
8835     * @requires $parse
8836     * @requires $sce
8837     *
8838     * @description
8839     *
8840     * Compiles a string with markup into an interpolation function. This service is used by the
8841     * HTML {@link ng.$compile $compile} service for data binding. See
8842     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8843     * interpolation markup.
8844     *
8845     *
8846     * ```js
8847     *   var $interpolate = ...; // injected
8848     *   var exp = $interpolate('Hello {{name | uppercase}}!');
8849     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8850     * ```
8851     *
8852     *
8853     * @param {string} text The text with markup to interpolate.
8854     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8855     *    embedded expression in order to return an interpolation function. Strings with no
8856     *    embedded expression will return null for the interpolation function.
8857     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8858     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8859     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8860     *    provides Strict Contextual Escaping for details.
8861     * @returns {function(context)} an interpolation function which is used to compute the
8862     *    interpolated string. The function has these parameters:
8863     *
8864     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8865     *      against.
8866     *
8867     */
8868    function $interpolate(text, mustHaveExpression, trustedContext) {
8869      var startIndex,
8870          endIndex,
8871          index = 0,
8872          parts = [],
8873          length = text.length,
8874          hasInterpolation = false,
8875          fn,
8876          exp,
8877          concat = [];
8878
8879      while(index < length) {
8880        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8881             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8882          (index != startIndex) && parts.push(text.substring(index, startIndex));
8883          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8884          fn.exp = exp;
8885          index = endIndex + endSymbolLength;
8886          hasInterpolation = true;
8887        } else {
8888          // we did not find anything, so we have to add the remainder to the parts array
8889          (index != length) && parts.push(text.substring(index));
8890          index = length;
8891        }
8892      }
8893
8894      if (!(length = parts.length)) {
8895        // we added, nothing, must have been an empty string.
8896        parts.push('');
8897        length = 1;
8898      }
8899
8900      // Concatenating expressions makes it hard to reason about whether some combination of
8901      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8902      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8903      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8904      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8905      // the load when auditing for XSS issues.
8906      if (trustedContext && parts.length > 1) {
8907          throw $interpolateMinErr('noconcat',
8908              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8909              "interpolations that concatenate multiple expressions when a trusted value is " +
8910              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8911      }
8912
8913      if (!mustHaveExpression  || hasInterpolation) {
8914        concat.length = length;
8915        fn = function(context) {
8916          try {
8917            for(var i = 0, ii = length, part; i<ii; i++) {
8918              if (typeof (part = parts[i]) == 'function') {
8919                part = part(context);
8920                if (trustedContext) {
8921                  part = $sce.getTrusted(trustedContext, part);
8922                } else {
8923                  part = $sce.valueOf(part);
8924                }
8925                if (part == null) { // null || undefined
8926                  part = '';
8927                } else {
8928                  switch (typeof part) {
8929                    case 'string':
8930                    {
8931                      break;
8932                    }
8933                    case 'number':
8934                    {
8935                      part = '' + part;
8936                      break;
8937                    }
8938                    default:
8939                    {
8940                      part = toJson(part);
8941                    }
8942                  }
8943                }
8944              }
8945              concat[i] = part;
8946            }
8947            return concat.join('');
8948          }
8949          catch(err) {
8950            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8951                err.toString());
8952            $exceptionHandler(newErr);
8953          }
8954        };
8955        fn.exp = text;
8956        fn.parts = parts;
8957        return fn;
8958      }
8959    }
8960
8961
8962    /**
8963     * @ngdoc method
8964     * @name $interpolate#startSymbol
8965     * @description
8966     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8967     *
8968     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
8969     * the symbol.
8970     *
8971     * @returns {string} start symbol.
8972     */
8973    $interpolate.startSymbol = function() {
8974      return startSymbol;
8975    };
8976
8977
8978    /**
8979     * @ngdoc method
8980     * @name $interpolate#endSymbol
8981     * @description
8982     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8983     *
8984     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
8985     * the symbol.
8986     *
8987     * @returns {string} end symbol.
8988     */
8989    $interpolate.endSymbol = function() {
8990      return endSymbol;
8991    };
8992
8993    return $interpolate;
8994  }];
8995}
8996
8997function $IntervalProvider() {
8998  this.$get = ['$rootScope', '$window', '$q',
8999       function($rootScope,   $window,   $q) {
9000    var intervals = {};
9001
9002
9003     /**
9004      * @ngdoc service
9005      * @name $interval
9006      *
9007      * @description
9008      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
9009      * milliseconds.
9010      *
9011      * The return value of registering an interval function is a promise. This promise will be
9012      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
9013      * run indefinitely if `count` is not defined. The value of the notification will be the
9014      * number of iterations that have run.
9015      * To cancel an interval, call `$interval.cancel(promise)`.
9016      *
9017      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
9018      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
9019      * time.
9020      *
9021      * <div class="alert alert-warning">
9022      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
9023      * with them.  In particular they are not automatically destroyed when a controller's scope or a
9024      * directive's element are destroyed.
9025      * You should take this into consideration and make sure to always cancel the interval at the
9026      * appropriate moment.  See the example below for more details on how and when to do this.
9027      * </div>
9028      *
9029      * @param {function()} fn A function that should be called repeatedly.
9030      * @param {number} delay Number of milliseconds between each function call.
9031      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
9032      *   indefinitely.
9033      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
9034      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
9035      * @returns {promise} A promise which will be notified on each iteration.
9036      *
9037      * @example
9038      * <example module="intervalExample">
9039      * <file name="index.html">
9040      *   <script>
9041      *     angular.module('intervalExample', [])
9042      *       .controller('ExampleController', ['$scope', '$interval',
9043      *         function($scope, $interval) {
9044      *           $scope.format = 'M/d/yy h:mm:ss a';
9045      *           $scope.blood_1 = 100;
9046      *           $scope.blood_2 = 120;
9047      *
9048      *           var stop;
9049      *           $scope.fight = function() {
9050      *             // Don't start a new fight if we are already fighting
9051      *             if ( angular.isDefined(stop) ) return;
9052      *
9053      *             stop = $interval(function() {
9054      *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
9055      *                 $scope.blood_1 = $scope.blood_1 - 3;
9056      *                 $scope.blood_2 = $scope.blood_2 - 4;
9057      *               } else {
9058      *                 $scope.stopFight();
9059      *               }
9060      *             }, 100);
9061      *           };
9062      *
9063      *           $scope.stopFight = function() {
9064      *             if (angular.isDefined(stop)) {
9065      *               $interval.cancel(stop);
9066      *               stop = undefined;
9067      *             }
9068      *           };
9069      *
9070      *           $scope.resetFight = function() {
9071      *             $scope.blood_1 = 100;
9072      *             $scope.blood_2 = 120;
9073      *           };
9074      *
9075      *           $scope.$on('$destroy', function() {
9076      *             // Make sure that the interval is destroyed too
9077      *             $scope.stopFight();
9078      *           });
9079      *         }])
9080      *       // Register the 'myCurrentTime' directive factory method.
9081      *       // We inject $interval and dateFilter service since the factory method is DI.
9082      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
9083      *         function($interval, dateFilter) {
9084      *           // return the directive link function. (compile function not needed)
9085      *           return function(scope, element, attrs) {
9086      *             var format,  // date format
9087      *                 stopTime; // so that we can cancel the time updates
9088      *
9089      *             // used to update the UI
9090      *             function updateTime() {
9091      *               element.text(dateFilter(new Date(), format));
9092      *             }
9093      *
9094      *             // watch the expression, and update the UI on change.
9095      *             scope.$watch(attrs.myCurrentTime, function(value) {
9096      *               format = value;
9097      *               updateTime();
9098      *             });
9099      *
9100      *             stopTime = $interval(updateTime, 1000);
9101      *
9102      *             // listen on DOM destroy (removal) event, and cancel the next UI update
9103      *             // to prevent updating time after the DOM element was removed.
9104      *             element.bind('$destroy', function() {
9105      *               $interval.cancel(stopTime);
9106      *             });
9107      *           }
9108      *         }]);
9109      *   </script>
9110      *
9111      *   <div>
9112      *     <div ng-controller="ExampleController">
9113      *       Date format: <input ng-model="format"> <hr/>
9114      *       Current time is: <span my-current-time="format"></span>
9115      *       <hr/>
9116      *       Blood 1 : <font color='red'>{{blood_1}}</font>
9117      *       Blood 2 : <font color='red'>{{blood_2}}</font>
9118      *       <button type="button" data-ng-click="fight()">Fight</button>
9119      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
9120      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
9121      *     </div>
9122      *   </div>
9123      *
9124      * </file>
9125      * </example>
9126      */
9127    function interval(fn, delay, count, invokeApply) {
9128      var setInterval = $window.setInterval,
9129          clearInterval = $window.clearInterval,
9130          deferred = $q.defer(),
9131          promise = deferred.promise,
9132          iteration = 0,
9133          skipApply = (isDefined(invokeApply) && !invokeApply);
9134
9135      count = isDefined(count) ? count : 0;
9136
9137      promise.then(null, null, fn);
9138
9139      promise.$$intervalId = setInterval(function tick() {
9140        deferred.notify(iteration++);
9141
9142        if (count > 0 && iteration >= count) {
9143          deferred.resolve(iteration);
9144          clearInterval(promise.$$intervalId);
9145          delete intervals[promise.$$intervalId];
9146        }
9147
9148        if (!skipApply) $rootScope.$apply();
9149
9150      }, delay);
9151
9152      intervals[promise.$$intervalId] = deferred;
9153
9154      return promise;
9155    }
9156
9157
9158     /**
9159      * @ngdoc method
9160      * @name $interval#cancel
9161      *
9162      * @description
9163      * Cancels a task associated with the `promise`.
9164      *
9165      * @param {promise} promise returned by the `$interval` function.
9166      * @returns {boolean} Returns `true` if the task was successfully canceled.
9167      */
9168    interval.cancel = function(promise) {
9169      if (promise && promise.$$intervalId in intervals) {
9170        intervals[promise.$$intervalId].reject('canceled');
9171        $window.clearInterval(promise.$$intervalId);
9172        delete intervals[promise.$$intervalId];
9173        return true;
9174      }
9175      return false;
9176    };
9177
9178    return interval;
9179  }];
9180}
9181
9182/**
9183 * @ngdoc service
9184 * @name $locale
9185 *
9186 * @description
9187 * $locale service provides localization rules for various Angular components. As of right now the
9188 * only public api is:
9189 *
9190 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
9191 */
9192function $LocaleProvider(){
9193  this.$get = function() {
9194    return {
9195      id: 'en-us',
9196
9197      NUMBER_FORMATS: {
9198        DECIMAL_SEP: '.',
9199        GROUP_SEP: ',',
9200        PATTERNS: [
9201          { // Decimal Pattern
9202            minInt: 1,
9203            minFrac: 0,
9204            maxFrac: 3,
9205            posPre: '',
9206            posSuf: '',
9207            negPre: '-',
9208            negSuf: '',
9209            gSize: 3,
9210            lgSize: 3
9211          },{ //Currency Pattern
9212            minInt: 1,
9213            minFrac: 2,
9214            maxFrac: 2,
9215            posPre: '\u00A4',
9216            posSuf: '',
9217            negPre: '(\u00A4',
9218            negSuf: ')',
9219            gSize: 3,
9220            lgSize: 3
9221          }
9222        ],
9223        CURRENCY_SYM: '$'
9224      },
9225
9226      DATETIME_FORMATS: {
9227        MONTH:
9228            'January,February,March,April,May,June,July,August,September,October,November,December'
9229            .split(','),
9230        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
9231        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
9232        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
9233        AMPMS: ['AM','PM'],
9234        medium: 'MMM d, y h:mm:ss a',
9235        short: 'M/d/yy h:mm a',
9236        fullDate: 'EEEE, MMMM d, y',
9237        longDate: 'MMMM d, y',
9238        mediumDate: 'MMM d, y',
9239        shortDate: 'M/d/yy',
9240        mediumTime: 'h:mm:ss a',
9241        shortTime: 'h:mm a'
9242      },
9243
9244      pluralCat: function(num) {
9245        if (num === 1) {
9246          return 'one';
9247        }
9248        return 'other';
9249      }
9250    };
9251  };
9252}
9253
9254var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
9255    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
9256var $locationMinErr = minErr('$location');
9257
9258
9259/**
9260 * Encode path using encodeUriSegment, ignoring forward slashes
9261 *
9262 * @param {string} path Path to encode
9263 * @returns {string}
9264 */
9265function encodePath(path) {
9266  var segments = path.split('/'),
9267      i = segments.length;
9268
9269  while (i--) {
9270    segments[i] = encodeUriSegment(segments[i]);
9271  }
9272
9273  return segments.join('/');
9274}
9275
9276function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
9277  var parsedUrl = urlResolve(absoluteUrl, appBase);
9278
9279  locationObj.$$protocol = parsedUrl.protocol;
9280  locationObj.$$host = parsedUrl.hostname;
9281  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
9282}
9283
9284
9285function parseAppUrl(relativeUrl, locationObj, appBase) {
9286  var prefixed = (relativeUrl.charAt(0) !== '/');
9287  if (prefixed) {
9288    relativeUrl = '/' + relativeUrl;
9289  }
9290  var match = urlResolve(relativeUrl, appBase);
9291  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
9292      match.pathname.substring(1) : match.pathname);
9293  locationObj.$$search = parseKeyValue(match.search);
9294  locationObj.$$hash = decodeURIComponent(match.hash);
9295
9296  // make sure path starts with '/';
9297  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
9298    locationObj.$$path = '/' + locationObj.$$path;
9299  }
9300}
9301
9302
9303/**
9304 *
9305 * @param {string} begin
9306 * @param {string} whole
9307 * @returns {string} returns text from whole after begin or undefined if it does not begin with
9308 *                   expected string.
9309 */
9310function beginsWith(begin, whole) {
9311  if (whole.indexOf(begin) === 0) {
9312    return whole.substr(begin.length);
9313  }
9314}
9315
9316
9317function stripHash(url) {
9318  var index = url.indexOf('#');
9319  return index == -1 ? url : url.substr(0, index);
9320}
9321
9322function trimEmptyHash(url) {
9323  return url.replace(/(#.+)|#$/, '$1');
9324}
9325
9326
9327function stripFile(url) {
9328  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9329}
9330
9331/* return the server only (scheme://host:port) */
9332function serverBase(url) {
9333  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9334}
9335
9336
9337/**
9338 * LocationHtml5Url represents an url
9339 * This object is exposed as $location service when HTML5 mode is enabled and supported
9340 *
9341 * @constructor
9342 * @param {string} appBase application base URL
9343 * @param {string} basePrefix url path prefix
9344 */
9345function LocationHtml5Url(appBase, basePrefix) {
9346  this.$$html5 = true;
9347  basePrefix = basePrefix || '';
9348  var appBaseNoFile = stripFile(appBase);
9349  parseAbsoluteUrl(appBase, this, appBase);
9350
9351
9352  /**
9353   * Parse given html5 (regular) url string into properties
9354   * @param {string} newAbsoluteUrl HTML5 url
9355   * @private
9356   */
9357  this.$$parse = function(url) {
9358    var pathUrl = beginsWith(appBaseNoFile, url);
9359    if (!isString(pathUrl)) {
9360      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9361          appBaseNoFile);
9362    }
9363
9364    parseAppUrl(pathUrl, this, appBase);
9365
9366    if (!this.$$path) {
9367      this.$$path = '/';
9368    }
9369
9370    this.$$compose();
9371  };
9372
9373  /**
9374   * Compose url and update `absUrl` property
9375   * @private
9376   */
9377  this.$$compose = function() {
9378    var search = toKeyValue(this.$$search),
9379        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9380
9381    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9382    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9383  };
9384
9385  this.$$parseLinkUrl = function(url, relHref) {
9386    var appUrl, prevAppUrl;
9387    var rewrittenUrl;
9388
9389    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
9390      prevAppUrl = appUrl;
9391      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
9392        rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9393      } else {
9394        rewrittenUrl = appBase + prevAppUrl;
9395      }
9396    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
9397      rewrittenUrl = appBaseNoFile + appUrl;
9398    } else if (appBaseNoFile == url + '/') {
9399      rewrittenUrl = appBaseNoFile;
9400    }
9401    if (rewrittenUrl) {
9402      this.$$parse(rewrittenUrl);
9403    }
9404    return !!rewrittenUrl;
9405  };
9406}
9407
9408
9409/**
9410 * LocationHashbangUrl represents url
9411 * This object is exposed as $location service when developer doesn't opt into html5 mode.
9412 * It also serves as the base class for html5 mode fallback on legacy browsers.
9413 *
9414 * @constructor
9415 * @param {string} appBase application base URL
9416 * @param {string} hashPrefix hashbang prefix
9417 */
9418function LocationHashbangUrl(appBase, hashPrefix) {
9419  var appBaseNoFile = stripFile(appBase);
9420
9421  parseAbsoluteUrl(appBase, this, appBase);
9422
9423
9424  /**
9425   * Parse given hashbang url into properties
9426   * @param {string} url Hashbang url
9427   * @private
9428   */
9429  this.$$parse = function(url) {
9430    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9431    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9432        ? beginsWith(hashPrefix, withoutBaseUrl)
9433        : (this.$$html5)
9434          ? withoutBaseUrl
9435          : '';
9436
9437    if (!isString(withoutHashUrl)) {
9438      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9439          hashPrefix);
9440    }
9441    parseAppUrl(withoutHashUrl, this, appBase);
9442
9443    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9444
9445    this.$$compose();
9446
9447    /*
9448     * In Windows, on an anchor node on documents loaded from
9449     * the filesystem, the browser will return a pathname
9450     * prefixed with the drive name ('/C:/path') when a
9451     * pathname without a drive is set:
9452     *  * a.setAttribute('href', '/foo')
9453     *   * a.pathname === '/C:/foo' //true
9454     *
9455     * Inside of Angular, we're always using pathnames that
9456     * do not include drive names for routing.
9457     */
9458    function removeWindowsDriveName (path, url, base) {
9459      /*
9460      Matches paths for file protocol on windows,
9461      such as /C:/foo/bar, and captures only /foo/bar.
9462      */
9463      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
9464
9465      var firstPathSegmentMatch;
9466
9467      //Get the relative path from the input URL.
9468      if (url.indexOf(base) === 0) {
9469        url = url.replace(base, '');
9470      }
9471
9472      // The input URL intentionally contains a first path segment that ends with a colon.
9473      if (windowsFilePathExp.exec(url)) {
9474        return path;
9475      }
9476
9477      firstPathSegmentMatch = windowsFilePathExp.exec(path);
9478      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9479    }
9480  };
9481
9482  /**
9483   * Compose hashbang url and update `absUrl` property
9484   * @private
9485   */
9486  this.$$compose = function() {
9487    var search = toKeyValue(this.$$search),
9488        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9489
9490    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9491    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9492  };
9493
9494  this.$$parseLinkUrl = function(url, relHref) {
9495    if(stripHash(appBase) == stripHash(url)) {
9496      this.$$parse(url);
9497      return true;
9498    }
9499    return false;
9500  };
9501}
9502
9503
9504/**
9505 * LocationHashbangUrl represents url
9506 * This object is exposed as $location service when html5 history api is enabled but the browser
9507 * does not support it.
9508 *
9509 * @constructor
9510 * @param {string} appBase application base URL
9511 * @param {string} hashPrefix hashbang prefix
9512 */
9513function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9514  this.$$html5 = true;
9515  LocationHashbangUrl.apply(this, arguments);
9516
9517  var appBaseNoFile = stripFile(appBase);
9518
9519  this.$$parseLinkUrl = function(url, relHref) {
9520    var rewrittenUrl;
9521    var appUrl;
9522
9523    if ( appBase == stripHash(url) ) {
9524      rewrittenUrl = url;
9525    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
9526      rewrittenUrl = appBase + hashPrefix + appUrl;
9527    } else if ( appBaseNoFile === url + '/') {
9528      rewrittenUrl = appBaseNoFile;
9529    }
9530    if (rewrittenUrl) {
9531      this.$$parse(rewrittenUrl);
9532    }
9533    return !!rewrittenUrl;
9534  };
9535
9536  this.$$compose = function() {
9537    var search = toKeyValue(this.$$search),
9538        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9539
9540    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9541    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
9542    this.$$absUrl = appBase + hashPrefix + this.$$url;
9543  };
9544
9545}
9546
9547
9548LocationHashbangInHtml5Url.prototype =
9549  LocationHashbangUrl.prototype =
9550  LocationHtml5Url.prototype = {
9551
9552  /**
9553   * Are we in html5 mode?
9554   * @private
9555   */
9556  $$html5: false,
9557
9558  /**
9559   * Has any change been replacing ?
9560   * @private
9561   */
9562  $$replace: false,
9563
9564  /**
9565   * @ngdoc method
9566   * @name $location#absUrl
9567   *
9568   * @description
9569   * This method is getter only.
9570   *
9571   * Return full url representation with all segments encoded according to rules specified in
9572   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9573   *
9574   * @return {string} full url
9575   */
9576  absUrl: locationGetter('$$absUrl'),
9577
9578  /**
9579   * @ngdoc method
9580   * @name $location#url
9581   *
9582   * @description
9583   * This method is getter / setter.
9584   *
9585   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9586   *
9587   * Change path, search and hash, when called with parameter and return `$location`.
9588   *
9589   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9590   * @return {string} url
9591   */
9592  url: function(url) {
9593    if (isUndefined(url))
9594      return this.$$url;
9595
9596    var match = PATH_MATCH.exec(url);
9597    if (match[1]) this.path(decodeURIComponent(match[1]));
9598    if (match[2] || match[1]) this.search(match[3] || '');
9599    this.hash(match[5] || '');
9600
9601    return this;
9602  },
9603
9604  /**
9605   * @ngdoc method
9606   * @name $location#protocol
9607   *
9608   * @description
9609   * This method is getter only.
9610   *
9611   * Return protocol of current url.
9612   *
9613   * @return {string} protocol of current url
9614   */
9615  protocol: locationGetter('$$protocol'),
9616
9617  /**
9618   * @ngdoc method
9619   * @name $location#host
9620   *
9621   * @description
9622   * This method is getter only.
9623   *
9624   * Return host of current url.
9625   *
9626   * @return {string} host of current url.
9627   */
9628  host: locationGetter('$$host'),
9629
9630  /**
9631   * @ngdoc method
9632   * @name $location#port
9633   *
9634   * @description
9635   * This method is getter only.
9636   *
9637   * Return port of current url.
9638   *
9639   * @return {Number} port
9640   */
9641  port: locationGetter('$$port'),
9642
9643  /**
9644   * @ngdoc method
9645   * @name $location#path
9646   *
9647   * @description
9648   * This method is getter / setter.
9649   *
9650   * Return path of current url when called without any parameter.
9651   *
9652   * Change path when called with parameter and return `$location`.
9653   *
9654   * Note: Path should always begin with forward slash (/), this method will add the forward slash
9655   * if it is missing.
9656   *
9657   * @param {(string|number)=} path New path
9658   * @return {string} path
9659   */
9660  path: locationGetterSetter('$$path', function(path) {
9661    path = path !== null ? path.toString() : '';
9662    return path.charAt(0) == '/' ? path : '/' + path;
9663  }),
9664
9665  /**
9666   * @ngdoc method
9667   * @name $location#search
9668   *
9669   * @description
9670   * This method is getter / setter.
9671   *
9672   * Return search part (as object) of current url when called without any parameter.
9673   *
9674   * Change search part when called with parameter and return `$location`.
9675   *
9676   *
9677   * ```js
9678   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
9679   * var searchObject = $location.search();
9680   * // => {foo: 'bar', baz: 'xoxo'}
9681   *
9682   *
9683   * // set foo to 'yipee'
9684   * $location.search('foo', 'yipee');
9685   * // => $location
9686   * ```
9687   *
9688   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9689   * hash object.
9690   *
9691   * When called with a single argument the method acts as a setter, setting the `search` component
9692   * of `$location` to the specified value.
9693   *
9694   * If the argument is a hash object containing an array of values, these values will be encoded
9695   * as duplicate search parameters in the url.
9696   *
9697   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
9698   * will override only a single search property.
9699   *
9700   * If `paramValue` is an array, it will override the property of the `search` component of
9701   * `$location` specified via the first argument.
9702   *
9703   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
9704   *
9705   * If `paramValue` is `true`, the property specified via the first argument will be added with no
9706   * value nor trailing equal sign.
9707   *
9708   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
9709   * one or more arguments returns `$location` object itself.
9710   */
9711  search: function(search, paramValue) {
9712    switch (arguments.length) {
9713      case 0:
9714        return this.$$search;
9715      case 1:
9716        if (isString(search) || isNumber(search)) {
9717          search = search.toString();
9718          this.$$search = parseKeyValue(search);
9719        } else if (isObject(search)) {
9720          // remove object undefined or null properties
9721          forEach(search, function(value, key) {
9722            if (value == null) delete search[key];
9723          });
9724
9725          this.$$search = search;
9726        } else {
9727          throw $locationMinErr('isrcharg',
9728              'The first argument of the `$location#search()` call must be a string or an object.');
9729        }
9730        break;
9731      default:
9732        if (isUndefined(paramValue) || paramValue === null) {
9733          delete this.$$search[search];
9734        } else {
9735          this.$$search[search] = paramValue;
9736        }
9737    }
9738
9739    this.$$compose();
9740    return this;
9741  },
9742
9743  /**
9744   * @ngdoc method
9745   * @name $location#hash
9746   *
9747   * @description
9748   * This method is getter / setter.
9749   *
9750   * Return hash fragment when called without any parameter.
9751   *
9752   * Change hash fragment when called with parameter and return `$location`.
9753   *
9754   * @param {(string|number)=} hash New hash fragment
9755   * @return {string} hash
9756   */
9757  hash: locationGetterSetter('$$hash', function(hash) {
9758    return hash !== null ? hash.toString() : '';
9759  }),
9760
9761  /**
9762   * @ngdoc method
9763   * @name $location#replace
9764   *
9765   * @description
9766   * If called, all changes to $location during current `$digest` will be replacing current history
9767   * record, instead of adding new one.
9768   */
9769  replace: function() {
9770    this.$$replace = true;
9771    return this;
9772  }
9773};
9774
9775function locationGetter(property) {
9776  return function() {
9777    return this[property];
9778  };
9779}
9780
9781
9782function locationGetterSetter(property, preprocess) {
9783  return function(value) {
9784    if (isUndefined(value))
9785      return this[property];
9786
9787    this[property] = preprocess(value);
9788    this.$$compose();
9789
9790    return this;
9791  };
9792}
9793
9794
9795/**
9796 * @ngdoc service
9797 * @name $location
9798 *
9799 * @requires $rootElement
9800 *
9801 * @description
9802 * The $location service parses the URL in the browser address bar (based on the
9803 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9804 * available to your application. Changes to the URL in the address bar are reflected into
9805 * $location service and changes to $location are reflected into the browser address bar.
9806 *
9807 * **The $location service:**
9808 *
9809 * - Exposes the current URL in the browser address bar, so you can
9810 *   - Watch and observe the URL.
9811 *   - Change the URL.
9812 * - Synchronizes the URL with the browser when the user
9813 *   - Changes the address bar.
9814 *   - Clicks the back or forward button (or clicks a History link).
9815 *   - Clicks on a link.
9816 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9817 *
9818 * For more information see {@link guide/$location Developer Guide: Using $location}
9819 */
9820
9821/**
9822 * @ngdoc provider
9823 * @name $locationProvider
9824 * @description
9825 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9826 */
9827function $LocationProvider(){
9828  var hashPrefix = '',
9829      html5Mode = false;
9830
9831  /**
9832   * @ngdoc method
9833   * @name $locationProvider#hashPrefix
9834   * @description
9835   * @param {string=} prefix Prefix for hash part (containing path and search)
9836   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9837   */
9838  this.hashPrefix = function(prefix) {
9839    if (isDefined(prefix)) {
9840      hashPrefix = prefix;
9841      return this;
9842    } else {
9843      return hashPrefix;
9844    }
9845  };
9846
9847  /**
9848   * @ngdoc method
9849   * @name $locationProvider#html5Mode
9850   * @description
9851   * @param {boolean=} mode Use HTML5 strategy if available.
9852   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9853   */
9854  this.html5Mode = function(mode) {
9855    if (isDefined(mode)) {
9856      html5Mode = mode;
9857      return this;
9858    } else {
9859      return html5Mode;
9860    }
9861  };
9862
9863  /**
9864   * @ngdoc event
9865   * @name $location#$locationChangeStart
9866   * @eventType broadcast on root scope
9867   * @description
9868   * Broadcasted before a URL will change. This change can be prevented by calling
9869   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9870   * details about event object. Upon successful change
9871   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9872   *
9873   * @param {Object} angularEvent Synthetic event object.
9874   * @param {string} newUrl New URL
9875   * @param {string=} oldUrl URL that was before it was changed.
9876   */
9877
9878  /**
9879   * @ngdoc event
9880   * @name $location#$locationChangeSuccess
9881   * @eventType broadcast on root scope
9882   * @description
9883   * Broadcasted after a URL was changed.
9884   *
9885   * @param {Object} angularEvent Synthetic event object.
9886   * @param {string} newUrl New URL
9887   * @param {string=} oldUrl URL that was before it was changed.
9888   */
9889
9890  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9891      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9892    var $location,
9893        LocationMode,
9894        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9895        initialUrl = $browser.url(),
9896        appBase;
9897
9898    if (html5Mode) {
9899      appBase = serverBase(initialUrl) + (baseHref || '/');
9900      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9901    } else {
9902      appBase = stripHash(initialUrl);
9903      LocationMode = LocationHashbangUrl;
9904    }
9905    $location = new LocationMode(appBase, '#' + hashPrefix);
9906    $location.$$parseLinkUrl(initialUrl, initialUrl);
9907
9908    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
9909
9910    $rootElement.on('click', function(event) {
9911      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9912      // currently we open nice url link and redirect then
9913
9914      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9915
9916      var elm = jqLite(event.target);
9917
9918      // traverse the DOM up to find first A tag
9919      while (lowercase(elm[0].nodeName) !== 'a') {
9920        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9921        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9922      }
9923
9924      var absHref = elm.prop('href');
9925      // get the actual href attribute - see
9926      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9927      var relHref = elm.attr('href') || elm.attr('xlink:href');
9928
9929      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9930        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9931        // an animation.
9932        absHref = urlResolve(absHref.animVal).href;
9933      }
9934
9935      // Ignore when url is started with javascript: or mailto:
9936      if (IGNORE_URI_REGEXP.test(absHref)) return;
9937
9938      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
9939        if ($location.$$parseLinkUrl(absHref, relHref)) {
9940          // We do a preventDefault for all urls that are part of the angular application,
9941          // in html5mode and also without, so that we are able to abort navigation without
9942          // getting double entries in the location history.
9943          event.preventDefault();
9944          // update location manually
9945          if ($location.absUrl() != $browser.url()) {
9946            $rootScope.$apply();
9947            // hack to work around FF6 bug 684208 when scenario runner clicks on links
9948            window.angular['ff-684208-preventDefault'] = true;
9949          }
9950        }
9951      }
9952    });
9953
9954
9955    // rewrite hashbang url <> html5 url
9956    if ($location.absUrl() != initialUrl) {
9957      $browser.url($location.absUrl(), true);
9958    }
9959
9960    // update $location when $browser url changes
9961    $browser.onUrlChange(function(newUrl) {
9962      if ($location.absUrl() != newUrl) {
9963        $rootScope.$evalAsync(function() {
9964          var oldUrl = $location.absUrl();
9965
9966          $location.$$parse(newUrl);
9967          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9968                                    oldUrl).defaultPrevented) {
9969            $location.$$parse(oldUrl);
9970            $browser.url(oldUrl);
9971          } else {
9972            afterLocationChange(oldUrl);
9973          }
9974        });
9975        if (!$rootScope.$$phase) $rootScope.$digest();
9976      }
9977    });
9978
9979    // update browser
9980    var changeCounter = 0;
9981    $rootScope.$watch(function $locationWatch() {
9982      var oldUrl = trimEmptyHash($browser.url());
9983      var newUrl = trimEmptyHash($location.absUrl());
9984      var currentReplace = $location.$$replace;
9985
9986      if (!changeCounter || oldUrl != newUrl) {
9987        changeCounter++;
9988        $rootScope.$evalAsync(function() {
9989          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9990              defaultPrevented) {
9991            $location.$$parse(oldUrl);
9992          } else {
9993            $browser.url($location.absUrl(), currentReplace);
9994            afterLocationChange(oldUrl);
9995          }
9996        });
9997      }
9998      $location.$$replace = false;
9999
10000      return changeCounter;
10001    });
10002
10003    return $location;
10004
10005    function afterLocationChange(oldUrl) {
10006      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
10007    }
10008}];
10009}
10010
10011/**
10012 * @ngdoc service
10013 * @name $log
10014 * @requires $window
10015 *
10016 * @description
10017 * Simple service for logging. Default implementation safely writes the message
10018 * into the browser's console (if present).
10019 *
10020 * The main purpose of this service is to simplify debugging and troubleshooting.
10021 *
10022 * The default is to log `debug` messages. You can use
10023 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
10024 *
10025 * @example
10026   <example module="logExample">
10027     <file name="script.js">
10028       angular.module('logExample', [])
10029         .controller('LogController', ['$scope', '$log', function($scope, $log) {
10030           $scope.$log = $log;
10031           $scope.message = 'Hello World!';
10032         }]);
10033     </file>
10034     <file name="index.html">
10035       <div ng-controller="LogController">
10036         <p>Reload this page with open console, enter text and hit the log button...</p>
10037         Message:
10038         <input type="text" ng-model="message"/>
10039         <button ng-click="$log.log(message)">log</button>
10040         <button ng-click="$log.warn(message)">warn</button>
10041         <button ng-click="$log.info(message)">info</button>
10042         <button ng-click="$log.error(message)">error</button>
10043       </div>
10044     </file>
10045   </example>
10046 */
10047
10048/**
10049 * @ngdoc provider
10050 * @name $logProvider
10051 * @description
10052 * Use the `$logProvider` to configure how the application logs messages
10053 */
10054function $LogProvider(){
10055  var debug = true,
10056      self = this;
10057
10058  /**
10059   * @ngdoc method
10060   * @name $logProvider#debugEnabled
10061   * @description
10062   * @param {boolean=} flag enable or disable debug level messages
10063   * @returns {*} current value if used as getter or itself (chaining) if used as setter
10064   */
10065  this.debugEnabled = function(flag) {
10066    if (isDefined(flag)) {
10067      debug = flag;
10068    return this;
10069    } else {
10070      return debug;
10071    }
10072  };
10073
10074  this.$get = ['$window', function($window){
10075    return {
10076      /**
10077       * @ngdoc method
10078       * @name $log#log
10079       *
10080       * @description
10081       * Write a log message
10082       */
10083      log: consoleLog('log'),
10084
10085      /**
10086       * @ngdoc method
10087       * @name $log#info
10088       *
10089       * @description
10090       * Write an information message
10091       */
10092      info: consoleLog('info'),
10093
10094      /**
10095       * @ngdoc method
10096       * @name $log#warn
10097       *
10098       * @description
10099       * Write a warning message
10100       */
10101      warn: consoleLog('warn'),
10102
10103      /**
10104       * @ngdoc method
10105       * @name $log#error
10106       *
10107       * @description
10108       * Write an error message
10109       */
10110      error: consoleLog('error'),
10111
10112      /**
10113       * @ngdoc method
10114       * @name $log#debug
10115       *
10116       * @description
10117       * Write a debug message
10118       */
10119      debug: (function () {
10120        var fn = consoleLog('debug');
10121
10122        return function() {
10123          if (debug) {
10124            fn.apply(self, arguments);
10125          }
10126        };
10127      }())
10128    };
10129
10130    function formatError(arg) {
10131      if (arg instanceof Error) {
10132        if (arg.stack) {
10133          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
10134              ? 'Error: ' + arg.message + '\n' + arg.stack
10135              : arg.stack;
10136        } else if (arg.sourceURL) {
10137          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
10138        }
10139      }
10140      return arg;
10141    }
10142
10143    function consoleLog(type) {
10144      var console = $window.console || {},
10145          logFn = console[type] || console.log || noop,
10146          hasApply = false;
10147
10148      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
10149      // The reason behind this is that console.log has type "object" in IE8...
10150      try {
10151        hasApply = !!logFn.apply;
10152      } catch (e) {}
10153
10154      if (hasApply) {
10155        return function() {
10156          var args = [];
10157          forEach(arguments, function(arg) {
10158            args.push(formatError(arg));
10159          });
10160          return logFn.apply(console, args);
10161        };
10162      }
10163
10164      // we are IE which either doesn't have window.console => this is noop and we do nothing,
10165      // or we are IE where console.log doesn't have apply so we log at least first 2 args
10166      return function(arg1, arg2) {
10167        logFn(arg1, arg2 == null ? '' : arg2);
10168      };
10169    }
10170  }];
10171}
10172
10173var $parseMinErr = minErr('$parse');
10174var promiseWarningCache = {};
10175var promiseWarning;
10176
10177// Sandboxing Angular Expressions
10178// ------------------------------
10179// Angular expressions are generally considered safe because these expressions only have direct
10180// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
10181// obtaining a reference to native JS functions such as the Function constructor.
10182//
10183// As an example, consider the following Angular expression:
10184//
10185//   {}.toString.constructor('alert("evil JS code")')
10186//
10187// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
10188// against the expression language, but not to prevent exploits that were enabled by exposing
10189// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
10190// practice and therefore we are not even trying to protect against interaction with an object
10191// explicitly exposed in this way.
10192//
10193// In general, it is not possible to access a Window object from an angular expression unless a
10194// window or some DOM object that has a reference to window is published onto a Scope.
10195// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
10196// native objects.
10197//
10198// See https://docs.angularjs.org/guide/security
10199
10200
10201function ensureSafeMemberName(name, fullExpression) {
10202  if (name === "__defineGetter__" || name === "__defineSetter__"
10203      || name === "__lookupGetter__" || name === "__lookupSetter__"
10204      || name === "__proto__") {
10205    throw $parseMinErr('isecfld',
10206        'Attempting to access a disallowed field in Angular expressions! '
10207        + 'Expression: {0}', fullExpression);
10208  }
10209  return name;
10210}
10211
10212function getStringValue(name, fullExpression) {
10213  // From the JavaScript docs:
10214  // Property names must be strings. This means that non-string objects cannot be used
10215  // as keys in an object. Any non-string object, including a number, is typecasted
10216  // into a string via the toString method.
10217  //
10218  // So, to ensure that we are checking the same `name` that JavaScript would use,
10219  // we cast it to a string, if possible.
10220  // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
10221  // this is, this will handle objects that misbehave.
10222  name = name + '';
10223  if (!isString(name)) {
10224    throw $parseMinErr('iseccst',
10225        'Cannot convert object to primitive value! '
10226        + 'Expression: {0}', fullExpression);
10227  }
10228  return name;
10229}
10230
10231function ensureSafeObject(obj, fullExpression) {
10232  // nifty check if obj is Function that is fast and works across iframes and other contexts
10233  if (obj) {
10234    if (obj.constructor === obj) {
10235      throw $parseMinErr('isecfn',
10236          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10237          fullExpression);
10238    } else if (// isWindow(obj)
10239        obj.document && obj.location && obj.alert && obj.setInterval) {
10240      throw $parseMinErr('isecwindow',
10241          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
10242          fullExpression);
10243    } else if (// isElement(obj)
10244        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
10245      throw $parseMinErr('isecdom',
10246          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
10247          fullExpression);
10248    } else if (// block Object so that we can't get hold of dangerous Object.* methods
10249        obj === Object) {
10250      throw $parseMinErr('isecobj',
10251          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
10252          fullExpression);
10253    }
10254  }
10255  return obj;
10256}
10257
10258var CALL = Function.prototype.call;
10259var APPLY = Function.prototype.apply;
10260var BIND = Function.prototype.bind;
10261
10262function ensureSafeFunction(obj, fullExpression) {
10263  if (obj) {
10264    if (obj.constructor === obj) {
10265      throw $parseMinErr('isecfn',
10266        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10267        fullExpression);
10268    } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
10269      throw $parseMinErr('isecff',
10270        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
10271        fullExpression);
10272    }
10273  }
10274}
10275
10276var OPERATORS = {
10277    /* jshint bitwise : false */
10278    'null':function(){return null;},
10279    'true':function(){return true;},
10280    'false':function(){return false;},
10281    undefined:noop,
10282    '+':function(self, locals, a,b){
10283      a=a(self, locals); b=b(self, locals);
10284      if (isDefined(a)) {
10285        if (isDefined(b)) {
10286          return a + b;
10287        }
10288        return a;
10289      }
10290      return isDefined(b)?b:undefined;},
10291    '-':function(self, locals, a,b){
10292          a=a(self, locals); b=b(self, locals);
10293          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
10294        },
10295    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
10296    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
10297    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
10298    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
10299    '=':noop,
10300    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
10301    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
10302    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
10303    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
10304    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
10305    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
10306    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
10307    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
10308    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
10309    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
10310    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
10311//    '|':function(self, locals, a,b){return a|b;},
10312    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
10313    '!':function(self, locals, a){return !a(self, locals);}
10314};
10315/* jshint bitwise: true */
10316var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
10317
10318
10319/////////////////////////////////////////
10320
10321
10322/**
10323 * @constructor
10324 */
10325var Lexer = function (options) {
10326  this.options = options;
10327};
10328
10329Lexer.prototype = {
10330  constructor: Lexer,
10331
10332  lex: function (text) {
10333    this.text = text;
10334
10335    this.index = 0;
10336    this.ch = undefined;
10337    this.lastCh = ':'; // can start regexp
10338
10339    this.tokens = [];
10340
10341    while (this.index < this.text.length) {
10342      this.ch = this.text.charAt(this.index);
10343      if (this.is('"\'')) {
10344        this.readString(this.ch);
10345      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
10346        this.readNumber();
10347      } else if (this.isIdent(this.ch)) {
10348        this.readIdent();
10349      } else if (this.is('(){}[].,;:?')) {
10350        this.tokens.push({
10351          index: this.index,
10352          text: this.ch
10353        });
10354        this.index++;
10355      } else if (this.isWhitespace(this.ch)) {
10356        this.index++;
10357        continue;
10358      } else {
10359        var ch2 = this.ch + this.peek();
10360        var ch3 = ch2 + this.peek(2);
10361        var fn = OPERATORS[this.ch];
10362        var fn2 = OPERATORS[ch2];
10363        var fn3 = OPERATORS[ch3];
10364        if (fn3) {
10365          this.tokens.push({index: this.index, text: ch3, fn: fn3});
10366          this.index += 3;
10367        } else if (fn2) {
10368          this.tokens.push({index: this.index, text: ch2, fn: fn2});
10369          this.index += 2;
10370        } else if (fn) {
10371          this.tokens.push({
10372            index: this.index,
10373            text: this.ch,
10374            fn: fn
10375          });
10376          this.index += 1;
10377        } else {
10378          this.throwError('Unexpected next character ', this.index, this.index + 1);
10379        }
10380      }
10381      this.lastCh = this.ch;
10382    }
10383    return this.tokens;
10384  },
10385
10386  is: function(chars) {
10387    return chars.indexOf(this.ch) !== -1;
10388  },
10389
10390  was: function(chars) {
10391    return chars.indexOf(this.lastCh) !== -1;
10392  },
10393
10394  peek: function(i) {
10395    var num = i || 1;
10396    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
10397  },
10398
10399  isNumber: function(ch) {
10400    return ('0' <= ch && ch <= '9');
10401  },
10402
10403  isWhitespace: function(ch) {
10404    // IE treats non-breaking space as \u00A0
10405    return (ch === ' ' || ch === '\r' || ch === '\t' ||
10406            ch === '\n' || ch === '\v' || ch === '\u00A0');
10407  },
10408
10409  isIdent: function(ch) {
10410    return ('a' <= ch && ch <= 'z' ||
10411            'A' <= ch && ch <= 'Z' ||
10412            '_' === ch || ch === '$');
10413  },
10414
10415  isExpOperator: function(ch) {
10416    return (ch === '-' || ch === '+' || this.isNumber(ch));
10417  },
10418
10419  throwError: function(error, start, end) {
10420    end = end || this.index;
10421    var colStr = (isDefined(start)
10422            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10423            : ' ' + end);
10424    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10425        error, colStr, this.text);
10426  },
10427
10428  readNumber: function() {
10429    var number = '';
10430    var start = this.index;
10431    while (this.index < this.text.length) {
10432      var ch = lowercase(this.text.charAt(this.index));
10433      if (ch == '.' || this.isNumber(ch)) {
10434        number += ch;
10435      } else {
10436        var peekCh = this.peek();
10437        if (ch == 'e' && this.isExpOperator(peekCh)) {
10438          number += ch;
10439        } else if (this.isExpOperator(ch) &&
10440            peekCh && this.isNumber(peekCh) &&
10441            number.charAt(number.length - 1) == 'e') {
10442          number += ch;
10443        } else if (this.isExpOperator(ch) &&
10444            (!peekCh || !this.isNumber(peekCh)) &&
10445            number.charAt(number.length - 1) == 'e') {
10446          this.throwError('Invalid exponent');
10447        } else {
10448          break;
10449        }
10450      }
10451      this.index++;
10452    }
10453    number = 1 * number;
10454    this.tokens.push({
10455      index: start,
10456      text: number,
10457      literal: true,
10458      constant: true,
10459      fn: function() { return number; }
10460    });
10461  },
10462
10463  readIdent: function() {
10464    var parser = this;
10465
10466    var ident = '';
10467    var start = this.index;
10468
10469    var lastDot, peekIndex, methodName, ch;
10470
10471    while (this.index < this.text.length) {
10472      ch = this.text.charAt(this.index);
10473      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10474        if (ch === '.') lastDot = this.index;
10475        ident += ch;
10476      } else {
10477        break;
10478      }
10479      this.index++;
10480    }
10481
10482    //check if this is not a method invocation and if it is back out to last dot
10483    if (lastDot) {
10484      peekIndex = this.index;
10485      while (peekIndex < this.text.length) {
10486        ch = this.text.charAt(peekIndex);
10487        if (ch === '(') {
10488          methodName = ident.substr(lastDot - start + 1);
10489          ident = ident.substr(0, lastDot - start);
10490          this.index = peekIndex;
10491          break;
10492        }
10493        if (this.isWhitespace(ch)) {
10494          peekIndex++;
10495        } else {
10496          break;
10497        }
10498      }
10499    }
10500
10501
10502    var token = {
10503      index: start,
10504      text: ident
10505    };
10506
10507    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10508    if (OPERATORS.hasOwnProperty(ident)) {
10509      token.fn = OPERATORS[ident];
10510      token.literal = true;
10511      token.constant = true;
10512    } else {
10513      var getter = getterFn(ident, this.options, this.text);
10514      token.fn = extend(function(self, locals) {
10515        return (getter(self, locals));
10516      }, {
10517        assign: function(self, value) {
10518          return setter(self, ident, value, parser.text, parser.options);
10519        }
10520      });
10521    }
10522
10523    this.tokens.push(token);
10524
10525    if (methodName) {
10526      this.tokens.push({
10527        index:lastDot,
10528        text: '.'
10529      });
10530      this.tokens.push({
10531        index: lastDot + 1,
10532        text: methodName
10533      });
10534    }
10535  },
10536
10537  readString: function(quote) {
10538    var start = this.index;
10539    this.index++;
10540    var string = '';
10541    var rawString = quote;
10542    var escape = false;
10543    while (this.index < this.text.length) {
10544      var ch = this.text.charAt(this.index);
10545      rawString += ch;
10546      if (escape) {
10547        if (ch === 'u') {
10548          var hex = this.text.substring(this.index + 1, this.index + 5);
10549          if (!hex.match(/[\da-f]{4}/i))
10550            this.throwError('Invalid unicode escape [\\u' + hex + ']');
10551          this.index += 4;
10552          string += String.fromCharCode(parseInt(hex, 16));
10553        } else {
10554          var rep = ESCAPE[ch];
10555          string = string + (rep || ch);
10556        }
10557        escape = false;
10558      } else if (ch === '\\') {
10559        escape = true;
10560      } else if (ch === quote) {
10561        this.index++;
10562        this.tokens.push({
10563          index: start,
10564          text: rawString,
10565          string: string,
10566          literal: true,
10567          constant: true,
10568          fn: function() { return string; }
10569        });
10570        return;
10571      } else {
10572        string += ch;
10573      }
10574      this.index++;
10575    }
10576    this.throwError('Unterminated quote', start);
10577  }
10578};
10579
10580
10581/**
10582 * @constructor
10583 */
10584var Parser = function (lexer, $filter, options) {
10585  this.lexer = lexer;
10586  this.$filter = $filter;
10587  this.options = options;
10588};
10589
10590Parser.ZERO = extend(function () {
10591  return 0;
10592}, {
10593  constant: true
10594});
10595
10596Parser.prototype = {
10597  constructor: Parser,
10598
10599  parse: function (text) {
10600    this.text = text;
10601
10602    this.tokens = this.lexer.lex(text);
10603
10604    var value = this.statements();
10605
10606    if (this.tokens.length !== 0) {
10607      this.throwError('is an unexpected token', this.tokens[0]);
10608    }
10609
10610    value.literal = !!value.literal;
10611    value.constant = !!value.constant;
10612
10613    return value;
10614  },
10615
10616  primary: function () {
10617    var primary;
10618    if (this.expect('(')) {
10619      primary = this.filterChain();
10620      this.consume(')');
10621    } else if (this.expect('[')) {
10622      primary = this.arrayDeclaration();
10623    } else if (this.expect('{')) {
10624      primary = this.object();
10625    } else {
10626      var token = this.expect();
10627      primary = token.fn;
10628      if (!primary) {
10629        this.throwError('not a primary expression', token);
10630      }
10631      primary.literal = !!token.literal;
10632      primary.constant = !!token.constant;
10633    }
10634
10635    var next, context;
10636    while ((next = this.expect('(', '[', '.'))) {
10637      if (next.text === '(') {
10638        primary = this.functionCall(primary, context);
10639        context = null;
10640      } else if (next.text === '[') {
10641        context = primary;
10642        primary = this.objectIndex(primary);
10643      } else if (next.text === '.') {
10644        context = primary;
10645        primary = this.fieldAccess(primary);
10646      } else {
10647        this.throwError('IMPOSSIBLE');
10648      }
10649    }
10650    return primary;
10651  },
10652
10653  throwError: function(msg, token) {
10654    throw $parseMinErr('syntax',
10655        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10656          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10657  },
10658
10659  peekToken: function() {
10660    if (this.tokens.length === 0)
10661      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10662    return this.tokens[0];
10663  },
10664
10665  peek: function(e1, e2, e3, e4) {
10666    if (this.tokens.length > 0) {
10667      var token = this.tokens[0];
10668      var t = token.text;
10669      if (t === e1 || t === e2 || t === e3 || t === e4 ||
10670          (!e1 && !e2 && !e3 && !e4)) {
10671        return token;
10672      }
10673    }
10674    return false;
10675  },
10676
10677  expect: function(e1, e2, e3, e4){
10678    var token = this.peek(e1, e2, e3, e4);
10679    if (token) {
10680      this.tokens.shift();
10681      return token;
10682    }
10683    return false;
10684  },
10685
10686  consume: function(e1){
10687    if (!this.expect(e1)) {
10688      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10689    }
10690  },
10691
10692  unaryFn: function(fn, right) {
10693    return extend(function(self, locals) {
10694      return fn(self, locals, right);
10695    }, {
10696      constant:right.constant
10697    });
10698  },
10699
10700  ternaryFn: function(left, middle, right){
10701    return extend(function(self, locals){
10702      return left(self, locals) ? middle(self, locals) : right(self, locals);
10703    }, {
10704      constant: left.constant && middle.constant && right.constant
10705    });
10706  },
10707
10708  binaryFn: function(left, fn, right) {
10709    return extend(function(self, locals) {
10710      return fn(self, locals, left, right);
10711    }, {
10712      constant:left.constant && right.constant
10713    });
10714  },
10715
10716  statements: function() {
10717    var statements = [];
10718    while (true) {
10719      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10720        statements.push(this.filterChain());
10721      if (!this.expect(';')) {
10722        // optimize for the common case where there is only one statement.
10723        // TODO(size): maybe we should not support multiple statements?
10724        return (statements.length === 1)
10725            ? statements[0]
10726            : function(self, locals) {
10727                var value;
10728                for (var i = 0; i < statements.length; i++) {
10729                  var statement = statements[i];
10730                  if (statement) {
10731                    value = statement(self, locals);
10732                  }
10733                }
10734                return value;
10735              };
10736      }
10737    }
10738  },
10739
10740  filterChain: function() {
10741    var left = this.expression();
10742    var token;
10743    while (true) {
10744      if ((token = this.expect('|'))) {
10745        left = this.binaryFn(left, token.fn, this.filter());
10746      } else {
10747        return left;
10748      }
10749    }
10750  },
10751
10752  filter: function() {
10753    var token = this.expect();
10754    var fn = this.$filter(token.text);
10755    var argsFn = [];
10756    while (true) {
10757      if ((token = this.expect(':'))) {
10758        argsFn.push(this.expression());
10759      } else {
10760        var fnInvoke = function(self, locals, input) {
10761          var args = [input];
10762          for (var i = 0; i < argsFn.length; i++) {
10763            args.push(argsFn[i](self, locals));
10764          }
10765          return fn.apply(self, args);
10766        };
10767        return function() {
10768          return fnInvoke;
10769        };
10770      }
10771    }
10772  },
10773
10774  expression: function() {
10775    return this.assignment();
10776  },
10777
10778  assignment: function() {
10779    var left = this.ternary();
10780    var right;
10781    var token;
10782    if ((token = this.expect('='))) {
10783      if (!left.assign) {
10784        this.throwError('implies assignment but [' +
10785            this.text.substring(0, token.index) + '] can not be assigned to', token);
10786      }
10787      right = this.ternary();
10788      return function(scope, locals) {
10789        return left.assign(scope, right(scope, locals), locals);
10790      };
10791    }
10792    return left;
10793  },
10794
10795  ternary: function() {
10796    var left = this.logicalOR();
10797    var middle;
10798    var token;
10799    if ((token = this.expect('?'))) {
10800      middle = this.assignment();
10801      if ((token = this.expect(':'))) {
10802        return this.ternaryFn(left, middle, this.assignment());
10803      } else {
10804        this.throwError('expected :', token);
10805      }
10806    } else {
10807      return left;
10808    }
10809  },
10810
10811  logicalOR: function() {
10812    var left = this.logicalAND();
10813    var token;
10814    while (true) {
10815      if ((token = this.expect('||'))) {
10816        left = this.binaryFn(left, token.fn, this.logicalAND());
10817      } else {
10818        return left;
10819      }
10820    }
10821  },
10822
10823  logicalAND: function() {
10824    var left = this.equality();
10825    var token;
10826    if ((token = this.expect('&&'))) {
10827      left = this.binaryFn(left, token.fn, this.logicalAND());
10828    }
10829    return left;
10830  },
10831
10832  equality: function() {
10833    var left = this.relational();
10834    var token;
10835    if ((token = this.expect('==','!=','===','!=='))) {
10836      left = this.binaryFn(left, token.fn, this.equality());
10837    }
10838    return left;
10839  },
10840
10841  relational: function() {
10842    var left = this.additive();
10843    var token;
10844    if ((token = this.expect('<', '>', '<=', '>='))) {
10845      left = this.binaryFn(left, token.fn, this.relational());
10846    }
10847    return left;
10848  },
10849
10850  additive: function() {
10851    var left = this.multiplicative();
10852    var token;
10853    while ((token = this.expect('+','-'))) {
10854      left = this.binaryFn(left, token.fn, this.multiplicative());
10855    }
10856    return left;
10857  },
10858
10859  multiplicative: function() {
10860    var left = this.unary();
10861    var token;
10862    while ((token = this.expect('*','/','%'))) {
10863      left = this.binaryFn(left, token.fn, this.unary());
10864    }
10865    return left;
10866  },
10867
10868  unary: function() {
10869    var token;
10870    if (this.expect('+')) {
10871      return this.primary();
10872    } else if ((token = this.expect('-'))) {
10873      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10874    } else if ((token = this.expect('!'))) {
10875      return this.unaryFn(token.fn, this.unary());
10876    } else {
10877      return this.primary();
10878    }
10879  },
10880
10881  fieldAccess: function(object) {
10882    var parser = this;
10883    var field = this.expect().text;
10884    var getter = getterFn(field, this.options, this.text);
10885
10886    return extend(function(scope, locals, self) {
10887      return getter(self || object(scope, locals));
10888    }, {
10889      assign: function(scope, value, locals) {
10890        var o = object(scope, locals);
10891        if (!o) object.assign(scope, o = {});
10892        return setter(o, field, value, parser.text, parser.options);
10893      }
10894    });
10895  },
10896
10897  objectIndex: function(obj) {
10898    var parser = this;
10899
10900    var indexFn = this.expression();
10901    this.consume(']');
10902
10903    return extend(function(self, locals) {
10904      var o = obj(self, locals),
10905          i = getStringValue(indexFn(self, locals), parser.text),
10906          v, p;
10907
10908      ensureSafeMemberName(i, parser.text);
10909      if (!o) return undefined;
10910      v = ensureSafeObject(o[i], parser.text);
10911      if (v && v.then && parser.options.unwrapPromises) {
10912        p = v;
10913        if (!('$$v' in v)) {
10914          p.$$v = undefined;
10915          p.then(function(val) { p.$$v = val; });
10916        }
10917        v = v.$$v;
10918      }
10919      return v;
10920    }, {
10921      assign: function(self, value, locals) {
10922        var key = ensureSafeMemberName(getStringValue(indexFn(self, locals), parser.text), parser.text);
10923        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10924        var o = ensureSafeObject(obj(self, locals), parser.text);
10925        if (!o) obj.assign(self, o = {});
10926        return o[key] = value;
10927      }
10928    });
10929  },
10930
10931  functionCall: function(fn, contextGetter) {
10932    var argsFn = [];
10933    if (this.peekToken().text !== ')') {
10934      do {
10935        argsFn.push(this.expression());
10936      } while (this.expect(','));
10937    }
10938    this.consume(')');
10939
10940    var parser = this;
10941
10942    return function(scope, locals) {
10943      var args = [];
10944      var context = contextGetter ? contextGetter(scope, locals) : scope;
10945
10946      for (var i = 0; i < argsFn.length; i++) {
10947        args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
10948      }
10949      var fnPtr = fn(scope, locals, context) || noop;
10950
10951      ensureSafeObject(context, parser.text);
10952      ensureSafeFunction(fnPtr, parser.text);
10953
10954      // IE doesn't have apply for some native functions
10955      var v = fnPtr.apply
10956            ? fnPtr.apply(context, args)
10957            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10958
10959      return ensureSafeObject(v, parser.text);
10960    };
10961  },
10962
10963  // This is used with json array declaration
10964  arrayDeclaration: function () {
10965    var elementFns = [];
10966    var allConstant = true;
10967    if (this.peekToken().text !== ']') {
10968      do {
10969        if (this.peek(']')) {
10970          // Support trailing commas per ES5.1.
10971          break;
10972        }
10973        var elementFn = this.expression();
10974        elementFns.push(elementFn);
10975        if (!elementFn.constant) {
10976          allConstant = false;
10977        }
10978      } while (this.expect(','));
10979    }
10980    this.consume(']');
10981
10982    return extend(function(self, locals) {
10983      var array = [];
10984      for (var i = 0; i < elementFns.length; i++) {
10985        array.push(elementFns[i](self, locals));
10986      }
10987      return array;
10988    }, {
10989      literal: true,
10990      constant: allConstant
10991    });
10992  },
10993
10994  object: function () {
10995    var keyValues = [];
10996    var allConstant = true;
10997    if (this.peekToken().text !== '}') {
10998      do {
10999        if (this.peek('}')) {
11000          // Support trailing commas per ES5.1.
11001          break;
11002        }
11003        var token = this.expect(),
11004        key = token.string || token.text;
11005        this.consume(':');
11006        var value = this.expression();
11007        keyValues.push({key: key, value: value});
11008        if (!value.constant) {
11009          allConstant = false;
11010        }
11011      } while (this.expect(','));
11012    }
11013    this.consume('}');
11014
11015    return extend(function(self, locals) {
11016      var object = {};
11017      for (var i = 0; i < keyValues.length; i++) {
11018        var keyValue = keyValues[i];
11019        object[keyValue.key] = keyValue.value(self, locals);
11020      }
11021      return object;
11022    }, {
11023      literal: true,
11024      constant: allConstant
11025    });
11026  }
11027};
11028
11029
11030//////////////////////////////////////////////////
11031// Parser helper functions
11032//////////////////////////////////////////////////
11033
11034function setter(obj, path, setValue, fullExp, options) {
11035  ensureSafeObject(obj, fullExp);
11036
11037  //needed?
11038  options = options || {};
11039
11040  var element = path.split('.'), key;
11041  for (var i = 0; element.length > 1; i++) {
11042    key = ensureSafeMemberName(element.shift(), fullExp);
11043    var propertyObj = ensureSafeObject(obj[key], fullExp);
11044    if (!propertyObj) {
11045      propertyObj = {};
11046      obj[key] = propertyObj;
11047    }
11048    obj = propertyObj;
11049    if (obj.then && options.unwrapPromises) {
11050      promiseWarning(fullExp);
11051      if (!("$$v" in obj)) {
11052        (function(promise) {
11053          promise.then(function(val) { promise.$$v = val; }); }
11054        )(obj);
11055      }
11056      if (obj.$$v === undefined) {
11057        obj.$$v = {};
11058      }
11059      obj = obj.$$v;
11060    }
11061  }
11062  key = ensureSafeMemberName(element.shift(), fullExp);
11063  ensureSafeObject(obj[key], fullExp);
11064  obj[key] = setValue;
11065  return setValue;
11066}
11067
11068var getterFnCacheDefault = {};
11069var getterFnCacheExpensive = {};
11070
11071function isPossiblyDangerousMemberName(name) {
11072  return name == 'constructor';
11073}
11074
11075/**
11076 * Implementation of the "Black Hole" variant from:
11077 * - http://jsperf.com/angularjs-parse-getter/4
11078 * - http://jsperf.com/path-evaluation-simplified/7
11079 */
11080function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
11081  ensureSafeMemberName(key0, fullExp);
11082  ensureSafeMemberName(key1, fullExp);
11083  ensureSafeMemberName(key2, fullExp);
11084  ensureSafeMemberName(key3, fullExp);
11085  ensureSafeMemberName(key4, fullExp);
11086  var eso = function(o) {
11087    return ensureSafeObject(o, fullExp);
11088  };
11089  var expensiveChecks = options.expensiveChecks;
11090  var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
11091  var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
11092  var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
11093  var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
11094  var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
11095
11096  return !options.unwrapPromises
11097      ? function cspSafeGetter(scope, locals) {
11098          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
11099
11100          if (pathVal == null) return pathVal;
11101          pathVal = eso0(pathVal[key0]);
11102
11103          if (!key1) return pathVal;
11104          if (pathVal == null) return undefined;
11105          pathVal = eso1(pathVal[key1]);
11106
11107          if (!key2) return pathVal;
11108          if (pathVal == null) return undefined;
11109          pathVal = eso2(pathVal[key2]);
11110
11111          if (!key3) return pathVal;
11112          if (pathVal == null) return undefined;
11113          pathVal = eso3(pathVal[key3]);
11114
11115          if (!key4) return pathVal;
11116          if (pathVal == null) return undefined;
11117          pathVal = eso4(pathVal[key4]);
11118
11119          return pathVal;
11120        }
11121      : function cspSafePromiseEnabledGetter(scope, locals) {
11122          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
11123              promise;
11124
11125          if (pathVal == null) return pathVal;
11126
11127          pathVal = eso0(pathVal[key0]);
11128          if (pathVal && pathVal.then) {
11129            promiseWarning(fullExp);
11130            if (!("$$v" in pathVal)) {
11131              promise = pathVal;
11132              promise.$$v = undefined;
11133              promise.then(function(val) { promise.$$v = eso0(val); });
11134            }
11135            pathVal = eso0(pathVal.$$v);
11136          }
11137
11138          if (!key1) return pathVal;
11139          if (pathVal == null) return undefined;
11140          pathVal = eso1(pathVal[key1]);
11141          if (pathVal && pathVal.then) {
11142            promiseWarning(fullExp);
11143            if (!("$$v" in pathVal)) {
11144              promise = pathVal;
11145              promise.$$v = undefined;
11146              promise.then(function(val) { promise.$$v = eso1(val); });
11147            }
11148            pathVal = eso1(pathVal.$$v);
11149          }
11150
11151          if (!key2) return pathVal;
11152          if (pathVal == null) return undefined;
11153          pathVal = eso2(pathVal[key2]);
11154          if (pathVal && pathVal.then) {
11155            promiseWarning(fullExp);
11156            if (!("$$v" in pathVal)) {
11157              promise = pathVal;
11158              promise.$$v = undefined;
11159              promise.then(function(val) { promise.$$v = eso2(val); });
11160            }
11161            pathVal = eso2(pathVal.$$v);
11162          }
11163
11164          if (!key3) return pathVal;
11165          if (pathVal == null) return undefined;
11166          pathVal = eso3(pathVal[key3]);
11167          if (pathVal && pathVal.then) {
11168            promiseWarning(fullExp);
11169            if (!("$$v" in pathVal)) {
11170              promise = pathVal;
11171              promise.$$v = undefined;
11172              promise.then(function(val) { promise.$$v = eso3(val); });
11173            }
11174            pathVal = eso3(pathVal.$$v);
11175          }
11176
11177          if (!key4) return pathVal;
11178          if (pathVal == null) return undefined;
11179          pathVal = eso4(pathVal[key4]);
11180          if (pathVal && pathVal.then) {
11181            promiseWarning(fullExp);
11182            if (!("$$v" in pathVal)) {
11183              promise = pathVal;
11184              promise.$$v = undefined;
11185              promise.then(function(val) { promise.$$v = eso4(val); });
11186            }
11187            pathVal = eso4(pathVal.$$v);
11188          }
11189          return pathVal;
11190        };
11191}
11192
11193function getterFnWithExtraArgs(fn, fullExpression) {
11194  return function(s, l) {
11195    return fn(s, l, promiseWarning, ensureSafeObject, fullExpression);
11196  };
11197}
11198
11199function getterFn(path, options, fullExp) {
11200  var expensiveChecks = options.expensiveChecks;
11201  var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
11202  // Check whether the cache has this getter already.
11203  // We can use hasOwnProperty directly on the cache because we ensure,
11204  // see below, that the cache never stores a path called 'hasOwnProperty'
11205  if (getterFnCache.hasOwnProperty(path)) {
11206    return getterFnCache[path];
11207  }
11208
11209  var pathKeys = path.split('.'),
11210      pathKeysLength = pathKeys.length,
11211      fn;
11212
11213  // http://jsperf.com/angularjs-parse-getter/6
11214  if (options.csp) {
11215    if (pathKeysLength < 6) {
11216      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
11217                          options);
11218    } else {
11219      fn = function(scope, locals) {
11220        var i = 0, val;
11221        do {
11222          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
11223                                pathKeys[i++], fullExp, options)(scope, locals);
11224
11225          locals = undefined; // clear after first iteration
11226          scope = val;
11227        } while (i < pathKeysLength);
11228        return val;
11229      };
11230    }
11231  } else {
11232    var code = 'var p;\n';
11233    if (expensiveChecks) {
11234      code += 's = eso(s, fe);\nl = eso(l, fe);\n';
11235    }
11236    var needsEnsureSafeObject = expensiveChecks;
11237    forEach(pathKeys, function(key, index) {
11238      ensureSafeMemberName(key, fullExp);
11239      var lookupJs = (index
11240                      // we simply dereference 's' on any .dot notation
11241                      ? 's'
11242                      // but if we are first then we check locals first, and if so read it first
11243                      : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '["' + key + '"]';
11244      var wrapWithEso = expensiveChecks || isPossiblyDangerousMemberName(key);
11245      if (wrapWithEso) {
11246        lookupJs = 'eso(' + lookupJs + ', fe)';
11247        needsEnsureSafeObject = true;
11248      }
11249      code += 'if(s == null) return undefined;\n' +
11250              's=' + lookupJs + ';\n';
11251      if (options.unwrapPromises) {
11252        code += 'if (s && s.then) {\n' +
11253                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
11254                  ' if (!("$$v" in s)) {\n' +
11255                    ' p=s;\n' +
11256                    ' p.$$v = undefined;\n' +
11257                    ' p.then(function(v) {p.$$v=' + (wrapWithEso ? 'eso(v)' : 'v') + ';});\n' +
11258                    '}\n' +
11259                  ' s=' + (wrapWithEso ? 'eso(s.$$v)' : 's.$$v') + '\n' +
11260                '}\n';
11261
11262      }
11263    });
11264    code += 'return s;';
11265
11266    /* jshint -W054 */
11267    // s=scope, l=locals, pw=promiseWarning, eso=ensureSafeObject, fe=fullExpression
11268    var evaledFnGetter = new Function('s', 'l', 'pw', 'eso', 'fe', code);
11269    /* jshint +W054 */
11270    evaledFnGetter.toString = valueFn(code);
11271    if (needsEnsureSafeObject || options.unwrapPromises) {
11272      evaledFnGetter = getterFnWithExtraArgs(evaledFnGetter, fullExp);
11273    }
11274    fn = evaledFnGetter;
11275  }
11276
11277  // Only cache the value if it's not going to mess up the cache object
11278  // This is more performant that using Object.prototype.hasOwnProperty.call
11279  if (path !== 'hasOwnProperty') {
11280    getterFnCache[path] = fn;
11281  }
11282  return fn;
11283}
11284
11285///////////////////////////////////
11286
11287/**
11288 * @ngdoc service
11289 * @name $parse
11290 * @kind function
11291 *
11292 * @description
11293 *
11294 * Converts Angular {@link guide/expression expression} into a function.
11295 *
11296 * ```js
11297 *   var getter = $parse('user.name');
11298 *   var setter = getter.assign;
11299 *   var context = {user:{name:'angular'}};
11300 *   var locals = {user:{name:'local'}};
11301 *
11302 *   expect(getter(context)).toEqual('angular');
11303 *   setter(context, 'newValue');
11304 *   expect(context.user.name).toEqual('newValue');
11305 *   expect(getter(context, locals)).toEqual('local');
11306 * ```
11307 *
11308 *
11309 * @param {string} expression String expression to compile.
11310 * @returns {function(context, locals)} a function which represents the compiled expression:
11311 *
11312 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11313 *      are evaluated against (typically a scope object).
11314 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11315 *      `context`.
11316 *
11317 *    The returned function also has the following properties:
11318 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
11319 *        literal.
11320 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
11321 *        constant literals.
11322 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
11323 *        set to a function to change its value on the given context.
11324 *
11325 */
11326
11327
11328/**
11329 * @ngdoc provider
11330 * @name $parseProvider
11331 * @kind function
11332 *
11333 * @description
11334 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
11335 *  service.
11336 */
11337function $ParseProvider() {
11338  var cacheDefault = {};
11339  var cacheExpensive = {};
11340
11341  var $parseOptions = {
11342    csp: false,
11343    unwrapPromises: false,
11344    logPromiseWarnings: true,
11345    expensiveChecks: false
11346  };
11347
11348
11349  /**
11350   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11351   *
11352   * @ngdoc method
11353   * @name $parseProvider#unwrapPromises
11354   * @description
11355   *
11356   * **This feature is deprecated, see deprecation notes below for more info**
11357   *
11358   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
11359   * found at any part of the expression. In other words, if set to true, the expression will always
11360   * result in a non-promise value.
11361   *
11362   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
11363   * the fulfillment value is used in place of the promise while evaluating the expression.
11364   *
11365   * **Deprecation notice**
11366   *
11367   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
11368   * dichotomy between data access in templates (accessed as raw values) and controller code
11369   * (accessed as promises).
11370   *
11371   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
11372   * the model access there.
11373   *
11374   * Other downsides of automatic promise unwrapping:
11375   *
11376   * - when building components it's often desirable to receive the raw promises
11377   * - adds complexity and slows down expression evaluation
11378   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
11379   *   generated
11380   * - makes IDE auto-completion and tool support hard
11381   *
11382   * **Warning Logs**
11383   *
11384   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
11385   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
11386   * `$parseProvider.logPromiseWarnings(false)` api.
11387   *
11388   *
11389   * @param {boolean=} value New value.
11390   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11391   *                         setter.
11392   */
11393  this.unwrapPromises = function(value) {
11394    if (isDefined(value)) {
11395      $parseOptions.unwrapPromises = !!value;
11396      return this;
11397    } else {
11398      return $parseOptions.unwrapPromises;
11399    }
11400  };
11401
11402
11403  /**
11404   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11405   *
11406   * @ngdoc method
11407   * @name $parseProvider#logPromiseWarnings
11408   * @description
11409   *
11410   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11411   *
11412   * The default is set to `true`.
11413   *
11414   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11415   *
11416   * @param {boolean=} value New value.
11417   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11418   *                         setter.
11419   */
11420 this.logPromiseWarnings = function(value) {
11421    if (isDefined(value)) {
11422      $parseOptions.logPromiseWarnings = value;
11423      return this;
11424    } else {
11425      return $parseOptions.logPromiseWarnings;
11426    }
11427  };
11428
11429
11430  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
11431    $parseOptions.csp = $sniffer.csp;
11432    var $parseOptionsExpensive = {
11433      csp: $parseOptions.csp,
11434      unwrapPromises: $parseOptions.unwrapPromises,
11435      logPromiseWarnings: $parseOptions.logPromiseWarnings,
11436      expensiveChecks: true
11437    };
11438
11439    promiseWarning = function promiseWarningFn(fullExp) {
11440      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11441      promiseWarningCache[fullExp] = true;
11442      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11443          'Automatic unwrapping of promises in Angular expressions is deprecated.');
11444    };
11445
11446    return function(exp, expensiveChecks) {
11447      var parsedExpression;
11448
11449      switch (typeof exp) {
11450        case 'string':
11451
11452          var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
11453          if (cache.hasOwnProperty(exp)) {
11454            return cache[exp];
11455          }
11456
11457          var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
11458          var lexer = new Lexer(parseOptions);
11459          var parser = new Parser(lexer, $filter, parseOptions);
11460          parsedExpression = parser.parse(exp);
11461
11462          if (exp !== 'hasOwnProperty') {
11463            // Only cache the value if it's not going to mess up the cache object
11464            // This is more performant that using Object.prototype.hasOwnProperty.call
11465            cache[exp] = parsedExpression;
11466          }
11467
11468          return parsedExpression;
11469
11470        case 'function':
11471          return exp;
11472
11473        default:
11474          return noop;
11475      }
11476    };
11477  }];
11478}
11479
11480/**
11481 * @ngdoc service
11482 * @name $q
11483 * @requires $rootScope
11484 *
11485 * @description
11486 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
11487 * when they are done processing.
11488 *
11489 * This is an implementation of promises/deferred objects inspired by
11490 * [Kris Kowal's Q](https://github.com/kriskowal/q).
11491 *
11492 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11493 * interface for interacting with an object that represents the result of an action that is
11494 * performed asynchronously, and may or may not be finished at any given point in t
11494ime.
11495 *
11496 * From the perspective of dealing with error handling, deferred and promise APIs are to
11497 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11498 *
11499 * ```js
11500 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11501 *   // are available in the current lexical scope (they could have been injected or passed in).
11502 *
11503 *   function asyncGreet(name) {
11504 *     var deferred = $q.defer();
11505 *
11506 *     setTimeout(function() {
11507 *       deferred.notify('About to greet ' + name + '.');
11508 *
11509 *       if (okToGreet(name)) {
11510 *         deferred.resolve('Hello, ' + name + '!');
11511 *       } else {
11512 *         deferred.reject('Greeting ' + name + ' is not allowed.');
11513 *       }
11514 *     }, 1000);
11515 *
11516 *     return deferred.promise;
11517 *   }
11518 *
11519 *   var promise = asyncGreet('Robin Hood');
11520 *   promise.then(function(greeting) {
11521 *     alert('Success: ' + greeting);
11522 *   }, function(reason) {
11523 *     alert('Failed: ' + reason);
11524 *   }, function(update) {
11525 *     alert('Got notification: ' + update);
11526 *   });
11527 * ```
11528 *
11529 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11530 * comes in the way of guarantees that promise and deferred APIs make, see
11531 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11532 *
11533 * Additionally the promise api allows for composition that is very hard to do with the
11534 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11535 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11536 * section on serial or parallel joining of promises.
11537 *
11538 *
11539 * # The Deferred API
11540 *
11541 * A new instance of deferred is constructed by calling `$q.defer()`.
11542 *
11543 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11544 * that can be used for signaling the successful or unsuccessful completion, as well as the status
11545 * of the task.
11546 *
11547 * **Methods**
11548 *
11549 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11550 *   constructed via `$q.reject`, the promise will be rejected instead.
11551 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11552 *   resolving it with a rejection constructed via `$q.reject`.
11553 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11554 *   multiple times before the promise is either resolved or rejected.
11555 *
11556 * **Properties**
11557 *
11558 * - promise – `{Promise}` – promise object associated with this deferred.
11559 *
11560 *
11561 * # The Promise API
11562 *
11563 * A new promise instance is created when a deferred instance is created and can be retrieved by
11564 * calling `deferred.promise`.
11565 *
11566 * The purpose of the promise object is to allow for interested parties to get access to the result
11567 * of the deferred task when it completes.
11568 *
11569 * **Methods**
11570 *
11571 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11572 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11573 *   as soon as the result is available. The callbacks are called with a single argument: the result
11574 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11575 *   provide a progress indication, before the promise is resolved or rejected.
11576 *
11577 *   This method *returns a new promise* which is resolved or rejected via the return value of the
11578 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11579 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11580 *   method.
11581 *
11582 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11583 *
11584 *   Because `catch` is a reserved word in JavaScript and reserved keywords are not supported as
11585 *   property names by ES3, you'll need to invoke the method like `promise['catch'](callback)` or
11586 *  `promise.then(null, errorCallback)` to make your code IE8 and Android 2.x compatible.
11587 *
11588 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11589 *   but to do so without modifying the final value. This is useful to release resources or do some
11590 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11591 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11592 *   more information.
11593 *
11594 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11595 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11596 *   make your code IE8 and Android 2.x compatible.
11597 *
11598 * # Chaining promises
11599 *
11600 * Because calling the `then` method of a promise returns a new derived promise, it is easily
11601 * possible to create a chain of promises:
11602 *
11603 * ```js
11604 *   promiseB = promiseA.then(function(result) {
11605 *     return result + 1;
11606 *   });
11607 *
11608 *   // promiseB will be resolved immediately after promiseA is resolved and its value
11609 *   // will be the result of promiseA incremented by 1
11610 * ```
11611 *
11612 * It is possible to create chains of any length and since a promise can be resolved with another
11613 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11614 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11615 * $http's response interceptors.
11616 *
11617 *
11618 * # Differences between Kris Kowal's Q and $q
11619 *
11620 *  There are two main differences:
11621 *
11622 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11623 *   mechanism in angular, which means faster propagation of resolution or rejection into your
11624 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11625 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11626 *   all the important functionality needed for common async tasks.
11627 *
11628 *  # Testing
11629 *
11630 *  ```js
11631 *    it('should simulate promise', inject(function($q, $rootScope) {
11632 *      var deferred = $q.defer();
11633 *      var promise = deferred.promise;
11634 *      var resolvedValue;
11635 *
11636 *      promise.then(function(value) { resolvedValue = value; });
11637 *      expect(resolvedValue).toBeUndefined();
11638 *
11639 *      // Simulate resolving of promise
11640 *      deferred.resolve(123);
11641 *      // Note that the 'then' function does not get called synchronously.
11642 *      // This is because we want the promise API to always be async, whether or not
11643 *      // it got called synchronously or asynchronously.
11644 *      expect(resolvedValue).toBeUndefined();
11645 *
11646 *      // Propagate promise resolution to 'then' functions using $apply().
11647 *      $rootScope.$apply();
11648 *      expect(resolvedValue).toEqual(123);
11649 *    }));
11650 *  ```
11651 */
11652function $QProvider() {
11653
11654  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
11655    return qFactory(function(callback) {
11656      $rootScope.$evalAsync(callback);
11657    }, $exceptionHandler);
11658  }];
11659}
11660
11661
11662/**
11663 * Constructs a promise manager.
11664 *
11665 * @param {function(Function)} nextTick Function for executing functions in the next turn.
11666 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11667 *     debugging purposes.
11668 * @returns {object} Promise manager.
11669 */
11670function qFactory(nextTick, exceptionHandler) {
11671
11672  /**
11673   * @ngdoc method
11674   * @name $q#defer
11675   * @kind function
11676   *
11677   * @description
11678   * Creates a `Deferred` object which represents a task which will finish in the future.
11679   *
11680   * @returns {Deferred} Returns a new instance of deferred.
11681   */
11682  var defer = function() {
11683    var pending = [],
11684        value, deferred;
11685
11686    deferred = {
11687
11688      resolve: function(val) {
11689        if (pending) {
11690          var callbacks = pending;
11691          pending = undefined;
11692          value = ref(val);
11693
11694          if (callbacks.length) {
11695            nextTick(function() {
11696              var callback;
11697              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11698                callback = callbacks[i];
11699                value.then(callback[0], callback[1], callback[2]);
11700              }
11701            });
11702          }
11703        }
11704      },
11705
11706
11707      reject: function(reason) {
11708        deferred.resolve(createInternalRejectedPromise(reason));
11709      },
11710
11711
11712      notify: function(progress) {
11713        if (pending) {
11714          var callbacks = pending;
11715
11716          if (pending.length) {
11717            nextTick(function() {
11718              var callback;
11719              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11720                callback = callbacks[i];
11721                callback[2](progress);
11722              }
11723            });
11724          }
11725        }
11726      },
11727
11728
11729      promise: {
11730        then: function(callback, errback, progressback) {
11731          var result = defer();
11732
11733          var wrappedCallback = function(value) {
11734            try {
11735              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11736            } catch(e) {
11737              result.reject(e);
11738              exceptionHandler(e);
11739            }
11740          };
11741
11742          var wrappedErrback = function(reason) {
11743            try {
11744              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11745            } catch(e) {
11746              result.reject(e);
11747              exceptionHandler(e);
11748            }
11749          };
11750
11751          var wrappedProgressback = function(progress) {
11752            try {
11753              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11754            } catch(e) {
11755              exceptionHandler(e);
11756            }
11757          };
11758
11759          if (pending) {
11760            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11761          } else {
11762            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11763          }
11764
11765          return result.promise;
11766        },
11767
11768        "catch": function(callback) {
11769          return this.then(null, callback);
11770        },
11771
11772        "finally": function(callback) {
11773
11774          function makePromise(value, resolved) {
11775            var result = defer();
11776            if (resolved) {
11777              result.resolve(value);
11778            } else {
11779              result.reject(value);
11780            }
11781            return result.promise;
11782          }
11783
11784          function handleCallback(value, isResolved) {
11785            var callbackOutput = null;
11786            try {
11787              callbackOutput = (callback ||defaultCallback)();
11788            } catch(e) {
11789              return makePromise(e, false);
11790            }
11791            if (isPromiseLike(callbackOutput)) {
11792              return callbackOutput.then(function() {
11793                return makePromise(value, isResolved);
11794              }, function(error) {
11795                return makePromise(error, false);
11796              });
11797            } else {
11798              return makePromise(value, isResolved);
11799            }
11800          }
11801
11802          return this.then(function(value) {
11803            return handleCallback(value, true);
11804          }, function(error) {
11805            return handleCallback(error, false);
11806          });
11807        }
11808      }
11809    };
11810
11811    return deferred;
11812  };
11813
11814
11815  var ref = function(value) {
11816    if (isPromiseLike(value)) return value;
11817    return {
11818      then: function(callback) {
11819        var result = defer();
11820        nextTick(function() {
11821          result.resolve(callback(value));
11822        });
11823        return result.promise;
11824      }
11825    };
11826  };
11827
11828
11829  /**
11830   * @ngdoc method
11831   * @name $q#reject
11832   * @kind function
11833   *
11834   * @description
11835   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11836   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11837   * a promise chain, you don't need to worry about it.
11838   *
11839   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11840   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11841   * a promise error callback and you want to forward the error to the promise derived from the
11842   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11843   * `reject`.
11844   *
11845   * ```js
11846   *   promiseB = promiseA.then(function(result) {
11847   *     // success: do something and resolve promiseB
11848   *     //          with the old or a new result
11849   *     return result;
11850   *   }, function(reason) {
11851   *     // error: handle the error if possible and
11852   *     //        resolve promiseB with newPromiseOrValue,
11853   *     //        otherwise forward the rejection to promiseB
11854   *     if (canHandle(reason)) {
11855   *      // handle the error and recover
11856   *      return newPromiseOrValue;
11857   *     }
11858   *     return $q.reject(reason);
11859   *   });
11860   * ```
11861   *
11862   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11863   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11864   */
11865  var reject = function(reason) {
11866    var result = defer();
11867    result.reject(reason);
11868    return result.promise;
11869  };
11870
11871  var createInternalRejectedPromise = function(reason) {
11872    return {
11873      then: function(callback, errback) {
11874        var result = defer();
11875        nextTick(function() {
11876          try {
11877            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11878          } catch(e) {
11879            result.reject(e);
11880            exceptionHandler(e);
11881          }
11882        });
11883        return result.promise;
11884      }
11885    };
11886  };
11887
11888
11889  /**
11890   * @ngdoc method
11891   * @name $q#when
11892   * @kind function
11893   *
11894   * @description
11895   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11896   * This is useful when you are dealing with an object that might or might not be a promise, or if
11897   * the promise comes from a source that can't be trusted.
11898   *
11899   * @param {*} value Value or a promise
11900   * @returns {Promise} Returns a promise of the passed value or promise
11901   */
11902  var when = function(value, callback, errback, progressback) {
11903    var result = defer(),
11904        done;
11905
11906    var wrappedCallback = function(value) {
11907      try {
11908        return (isFunction(callback) ? callback : defaultCallback)(value);
11909      } catch (e) {
11910        exceptionHandler(e);
11911        return reject(e);
11912      }
11913    };
11914
11915    var wrappedErrback = function(reason) {
11916      try {
11917        return (isFunction(errback) ? errback : defaultErrback)(reason);
11918      } catch (e) {
11919        exceptionHandler(e);
11920        return reject(e);
11921      }
11922    };
11923
11924    var wrappedProgressback = function(progress) {
11925      try {
11926        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11927      } catch (e) {
11928        exceptionHandler(e);
11929      }
11930    };
11931
11932    nextTick(function() {
11933      ref(value).then(function(value) {
11934        if (done) return;
11935        done = true;
11936        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11937      }, function(reason) {
11938        if (done) return;
11939        done = true;
11940        result.resolve(wrappedErrback(reason));
11941      }, function(progress) {
11942        if (done) return;
11943        result.notify(wrappedProgressback(progress));
11944      });
11945    });
11946
11947    return result.promise;
11948  };
11949
11950
11951  function defaultCallback(value) {
11952    return value;
11953  }
11954
11955
11956  function defaultErrback(reason) {
11957    return reject(reason);
11958  }
11959
11960
11961  /**
11962   * @ngdoc method
11963   * @name $q#all
11964   * @kind function
11965   *
11966   * @description
11967   * Combines multiple promises into a single promise that is resolved when all of the input
11968   * promises are resolved.
11969   *
11970   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11971   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11972   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11973   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11974   *   with the same rejection value.
11975   */
11976  function all(promises) {
11977    var deferred = defer(),
11978        counter = 0,
11979        results = isArray(promises) ? [] : {};
11980
11981    forEach(promises, function(promise, key) {
11982      counter++;
11983      ref(promise).then(function(value) {
11984        if (results.hasOwnProperty(key)) return;
11985        results[key] = value;
11986        if (!(--counter)) deferred.resolve(results);
11987      }, function(reason) {
11988        if (results.hasOwnProperty(key)) return;
11989        deferred.reject(reason);
11990      });
11991    });
11992
11993    if (counter === 0) {
11994      deferred.resolve(results);
11995    }
11996
11997    return deferred.promise;
11998  }
11999
12000  return {
12001    defer: defer,
12002    reject: reject,
12003    when: when,
12004    all: all
12005  };
12006}
12007
12008function $$RAFProvider(){ //rAF
12009  this.$get = ['$window', '$timeout', function($window, $timeout) {
12010    var requestAnimationFrame = $window.requestAnimationFrame ||
12011                                $window.webkitRequestAnimationFrame ||
12012                                $window.mozRequestAnimationFrame;
12013
12014    var cancelAnimationFrame = $window.cancelAnimationFrame ||
12015                               $window.webkitCancelAnimationFrame ||
12016                               $window.mozCancelAnimationFrame ||
12017                               $window.webkitCancelRequestAnimationFrame;
12018
12019    var rafSupported = !!requestAnimationFrame;
12020    var raf = rafSupported
12021      ? function(fn) {
12022          var id = requestAnimationFrame(fn);
12023          return function() {
12024            cancelAnimationFrame(id);
12025          };
12026        }
12027      : function(fn) {
12028          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
12029          return function() {
12030            $timeout.cancel(timer);
12031          };
12032        };
12033
12034    raf.supported = rafSupported;
12035
12036    return raf;
12037  }];
12038}
12039
12040/**
12041 * DESIGN NOTES
12042 *
12043 * The design decisions behind the scope are heavily favored for speed and memory consumption.
12044 *
12045 * The typical use of scope is to watch the expressions, which most of the time return the same
12046 * value as last time so we optimize the operation.
12047 *
12048 * Closures construction is expensive in terms of speed as well as memory:
12049 *   - No closures, instead use prototypical inheritance for API
12050 *   - Internal state needs to be stored on scope directly, which means that private state is
12051 *     exposed as $$____ properties
12052 *
12053 * Loop operations are optimized by using while(count--) { ... }
12054 *   - this means that in order to keep the same order of execution as addition we have to add
12055 *     items to the array at the beginning (unshift) instead of at the end (push)
12056 *
12057 * Child scopes are created and removed often
12058 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
12059 *
12060 * There are few watches then a lot of observers. This is why you don't want the observer to be
12061 * implemented in the same way as watch. Watch requires return of initialization function which
12062 * are expensive to construct.
12063 */
12064
12065
12066/**
12067 * @ngdoc provider
12068 * @name $rootScopeProvider
12069 * @description
12070 *
12071 * Provider for the $rootScope service.
12072 */
12073
12074/**
12075 * @ngdoc method
12076 * @name $rootScopeProvider#digestTtl
12077 * @description
12078 *
12079 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
12080 * assuming that the model is unstable.
12081 *
12082 * The current default is 10 iterations.
12083 *
12084 * In complex applications it's possible that the dependencies between `$watch`s will result in
12085 * several digest iterations. However if an application needs more than the default 10 digest
12086 * iterations for its model to stabilize then you should investigate what is causing the model to
12087 * continuously change during the digest.
12088 *
12089 * Increasing the TTL could have performance implications, so you should not change it without
12090 * proper justification.
12091 *
12092 * @param {number} limit The number of digest iterations.
12093 */
12094
12095
12096/**
12097 * @ngdoc service
12098 * @name $rootScope
12099 * @description
12100 *
12101 * Every application has a single root {@link ng.$rootScope.Scope scope}.
12102 * All other scopes are descendant scopes of the root scope. Scopes provide separation
12103 * between the model and the view, via a mechanism for watching the model for changes.
12104 * They also provide an event emission/broadcast and subscription facility. See the
12105 * {@link guide/scope developer guide on scopes}.
12106 */
12107function $RootScopeProvider(){
12108  var TTL = 10;
12109  var $rootScopeMinErr = minErr('$rootScope');
12110  var lastDirtyWatch = null;
12111
12112  this.digestTtl = function(value) {
12113    if (arguments.length) {
12114      TTL = value;
12115    }
12116    return TTL;
12117  };
12118
12119  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
12120      function( $injector,   $exceptionHandler,   $parse,   $browser) {
12121
12122    /**
12123     * @ngdoc type
12124     * @name $rootScope.Scope
12125     *
12126     * @description
12127     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
12128     * {@link auto.$injector $injector}. Child scopes are created using the
12129     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
12130     * compiled HTML template is executed.)
12131     *
12132     * Here is a simple scope snippet to show how you can interact with the scope.
12133     * ```html
12134     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
12135     * ```
12136     *
12137     * # Inheritance
12138     * A scope can inherit from a parent scope, as in this example:
12139     * ```js
12140         var parent = $rootScope;
12141         var child = parent.$new();
12142
12143         parent.salutation = "Hello";
12144         child.name = "World";
12145         expect(child.salutation).toEqual('Hello');
12146
12147         child.salutation = "Welcome";
12148         expect(child.salutation).toEqual('Welcome');
12149         expect(parent.salutation).toEqual('Hello');
12150     * ```
12151     *
12152     *
12153     * @param {Object.<string, function()>=} providers Map of service factory which need to be
12154     *                                       provided for the current scope. Defaults to {@link ng}.
12155     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
12156     *                              append/override services provided by `providers`. This is handy
12157     *                              when unit-testing and having the need to override a default
12158     *                              service.
12159     * @returns {Object} Newly created scope.
12160     *
12161     */
12162    function Scope() {
12163      this.$id = nextUid();
12164      this.$$phase = this.$parent = this.$$watchers =
12165                     this.$$nextSibling = this.$$prevSibling =
12166                     this.$$childHead = this.$$childTail = null;
12167      this['this'] = this.$root =  this;
12168      this.$$destroyed = false;
12169      this.$$asyncQueue = [];
12170      this.$$postDigestQueue = [];
12171      this.$$listeners = {};
12172      this.$$listenerCount = {};
12173      this.$$isolateBindings = {};
12174    }
12175
12176    /**
12177     * @ngdoc property
12178     * @name $rootScope.Scope#$id
12179     *
12180     * @description
12181     * Unique scope ID (monotonically increasing) useful for debugging.
12182     */
12183
12184     /**
12185      * @ngdoc property
12186      * @name $rootScope.Scope#$parent
12187      *
12188      * @description
12189      * Reference to the parent scope.
12190      */
12191
12192      /**
12193       * @ngdoc property
12194       * @name $rootScope.Scope#$root
12195       *
12196       * @description
12197       * Reference to the root scope.
12198       */
12199
12200    Scope.prototype = {
12201      constructor: Scope,
12202      /**
12203       * @ngdoc method
12204       * @name $rootScope.Scope#$new
12205       * @kind function
12206       *
12207       * @description
12208       * Creates a new child {@link ng.$rootScope.Scope scope}.
12209       *
12210       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
12211       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
12212       *
12213       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
12214       * desired for the scope and its child scopes to be permanently detached from the parent and
12215       * thus stop participating in model change detection and listener notification by invoking.
12216       *
12217       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
12218       *         parent scope. The scope is isolated, as it can not see parent scope properties.
12219       *         When creating widgets, it is useful for the widget to not accidentally read parent
12220       *         state.
12221       *
12222       * @returns {Object} The newly created child scope.
12223       *
12224       */
12225      $new: function(isolate) {
12226        var ChildScope,
12227            child;
12228
12229        if (isolate) {
12230          child = new Scope();
12231          child.$root = this.$root;
12232          // ensure that there is just one async queue per $rootScope and its children
12233          child.$$asyncQueue = this.$$asyncQueue;
12234          child.$$postDigestQueue = this.$$postDigestQueue;
12235        } else {
12236          // Only create a child scope class if somebody asks for one,
12237          // but cache it to allow the VM to optimize lookups.
12238          if (!this.$$childScopeClass) {
12239            this.$$childScopeClass = function() {
12240              this.$$watchers = this.$$nextSibling =
12241                  this.$$childHead = this.$$childTail = null;
12242              this.$$listeners = {};
12243              this.$$listenerCount = {};
12244              this.$id = nextUid();
12245              this.$$childScopeClass = null;
12246            };
12247            this.$$childScopeClass.prototype = this;
12248          }
12249          child = new this.$$childScopeClass();
12250        }
12251        child['this'] = child;
12252        child.$parent = this;
12253        child.$$prevSibling = this.$$childTail;
12254        if (this.$$childHead) {
12255          this.$$childTail.$$nextSibling = child;
12256          this.$$childTail = child;
12257        } else {
12258          this.$$childHead = this.$$childTail = child;
12259        }
12260        return child;
12261      },
12262
12263      /**
12264       * @ngdoc method
12265       * @name $rootScope.Scope#$watch
12266       * @kind function
12267       *
12268       * @description
12269       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
12270       *
12271       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
12272       *   $digest()} and should return the value that will be watched. (Since
12273       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
12274       *   `watchExpression` can execute multiple times per
12275       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
12276       * - The `listener` is called only when the value from the current `watchExpression` and the
12277       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
12278       *   see below). Inequality is determined according to reference inequality,
12279       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
12280       *    via the `!==` Javascript operator, unless `objectEquality == true`
12281       *   (see next point)
12282       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
12283       *   according to the {@link angular.equals} function. To save the value of the object for
12284       *   later comparison, the {@link angular.copy} function is used. This therefore means that
12285       *   watching complex objects will have adverse memory and performance implications.
12286       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
12287       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
12288       *   iteration limit is 10 to prevent an infinite loop deadlock.
12289       *
12290       *
12291       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
12292       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
12293       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
12294       * change is detected, be prepared for multiple calls to your listener.)
12295       *
12296       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
12297       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
12298       * watcher. In rare cases, this is undesirable because the listener is called when the result
12299       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
12300       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
12301       * listener was called due to initialization.
12302       *
12303       * The example below contains an illustration of using a function as your $watch listener
12304       *
12305       *
12306       * # Example
12307       * ```js
12308           // let's assume that scope was dependency injected as the $rootScope
12309           var scope = $rootScope;
12310           scope.name = 'misko';
12311           scope.counter = 0;
12312
12313           expect(scope.counter).toEqual(0);
12314           scope.$watch('name', function(newValue, oldValue) {
12315             scope.counter = scope.counter + 1;
12316           });
12317           expect(scope.counter).toEqual(0);
12318
12319           scope.$digest();
12320           // the listener is always called during the first $digest loop after it was registered
12321           expect(scope.counter).toEqual(1);
12322
12323           scope.$digest();
12324           // but now it will not be called unless the value changes
12325           expect(scope.counter).toEqual(1);
12326
12327           scope.name = 'adam';
12328           scope.$digest();
12329           expect(scope.counter).toEqual(2);
12330
12331
12332
12333           // Using a listener function
12334           var food;
12335           scope.foodCounter = 0;
12336           expect(scope.foodCounter).toEqual(0);
12337           scope.$watch(
12338             // This is the listener function
12339             function() { return food; },
12340             // This is the change handler
12341             function(newValue, oldValue) {
12342               if ( newValue !== oldValue ) {
12343                 // Only increment the counter if the value changed
12344                 scope.foodCounter = scope.foodCounter + 1;
12345               }
12346             }
12347           );
12348           // No digest has been run so the counter will be zero
12349           expect(scope.foodCounter).toEqual(0);
12350
12351           // Run the digest but since food has not changed count will still be zero
12352           scope.$digest();
12353           expect(scope.foodCounter).toEqual(0);
12354
12355           // Update food and run digest.  Now the counter will increment
12356           food = 'cheeseburger';
12357           scope.$digest();
12358           expect(scope.foodCounter).toEqual(1);
12359
12360       * ```
12361       *
12362       *
12363       *
12364       * @param {(function()|string)} watchExpression Expression that is evaluated on each
12365       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
12366       *    a call to the `listener`.
12367       *
12368       *    - `string`: Evaluated as {@link guide/expression expression}
12369       *    - `function(scope)`: called with current `scope` as a parameter.
12370       * @param {(function()|string)=} listener Callback called whenever the return value of
12371       *   the `watchExpression` changes.
12372       *
12373       *    - `string`: Evaluated as {@link guide/expression expression}
12374       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
12375       *      parameters.
12376       *
12377       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
12378       *     comparing for reference equality.
12379       * @returns {function()} Returns a deregistration function for this listener.
12380       */
12381      $watch: function(watchExp, listener, objectEquality) {
12382        var scope = this,
12383            get = compileToFn(watchExp, 'watch'),
12384            array = scope.$$watchers,
12385            watcher = {
12386              fn: listener,
12387              last: initWatchVal,
12388              get: get,
12389              exp: watchExp,
12390              eq: !!objectEquality
12391            };
12392
12393        lastDirtyWatch = null;
12394
12395        // in the case user pass string, we need to compile it, do we really need this ?
12396        if (!isFunction(listener)) {
12397          var listenFn = compileToFn(listener || noop, 'listener');
12398          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
12399        }
12400
12401        if (typeof watchExp == 'string' && get.constant) {
12402          var originalFn = watcher.fn;
12403          watcher.fn = function(newVal, oldVal, scope) {
12404            originalFn.call(this, newVal, oldVal, scope);
12405            arrayRemove(array, watcher);
12406          };
12407        }
12408
12409        if (!array) {
12410          array = scope.$$watchers = [];
12411        }
12412        // we use unshift since we use a while loop in $digest for speed.
12413        // the while loop reads in reverse order.
12414        array.unshift(watcher);
12415
12416        return function deregisterWatch() {
12417          arrayRemove(array, watcher);
12418          lastDirtyWatch = null;
12419        };
12420      },
12421
12422
12423      /**
12424       * @ngdoc method
12425       * @name $rootScope.Scope#$watchCollection
12426       * @kind function
12427       *
12428       * @description
12429       * Shallow watches the properties of an object and fires whenever any of the properties change
12430       * (for arrays, this implies watching the array items; for object maps, this implies watching
12431       * the properties). If a change is detected, the `listener` callback is fired.
12432       *
12433       * - The `obj` collection is observed via standard $watch operation and is examined on every
12434       *   call to $digest() to see if any items have been added, removed, or moved.
12435       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
12436       *   adding, removing, and moving items belonging to an object or array.
12437       *
12438       *
12439       * # Example
12440       * ```js
12441          $scope.names = ['igor', 'matias', 'misko', 'james'];
12442          $scope.dataCount = 4;
12443
12444          $scope.$watchCollection('names', function(newNames, oldNames) {
12445            $scope.dataCount = newNames.length;
12446          });
12447
12448          expect($scope.dataCount).toEqual(4);
12449          $scope.$digest();
12450
12451          //still at 4 ... no changes
12452          expect($scope.dataCount).toEqual(4);
12453
12454          $scope.names.pop();
12455          $scope.$digest();
12456
12457          //now there's been a change
12458          expect($scope.dataCount).toEqual(3);
12459       * ```
12460       *
12461       *
12462       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12463       *    expression value should evaluate to an object or an array which is observed on each
12464       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12465       *    collection will trigger a call to the `listener`.
12466       *
12467       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12468       *    when a change is detected.
12469       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12470       *    - The `oldCollection` object is a copy of the former collection data.
12471       *      Due to performance considerations, the`oldCollection` value is computed only if the
12472       *      `listener` function declares two or more arguments.
12473       *    - The `scope` argument refers to the current scope.
12474       *
12475       * @returns {function()} Returns a de-registration function for this listener. When the
12476       *    de-registration function is executed, the internal watch operation is terminated.
12477       */
12478      $watchCollection: function(obj, listener) {
12479        var self = this;
12480        // the current value, updated on each dirty-check run
12481        var newValue;
12482        // a shallow copy of the newValue from the last dirty-check run,
12483        // updated to match newValue during dirty-check run
12484        var oldValue;
12485        // a shallow copy of the newValue from when the last change happened
12486        var veryOldValue;
12487        // only track veryOldValue if the listener is asking for it
12488        var trackVeryOldValue = (listener.length > 1);
12489        var changeDetected = 0;
12490        var objGetter = $parse(obj);
12491        var internalArray = [];
12492        var internalObject = {};
12493        var initRun = true;
12494        var oldLength = 0;
12495
12496        function $watchCollectionWatch() {
12497          newValue = objGetter(self);
12498          var newLength, key, bothNaN;
12499
12500          if (!isObject(newValue)) { // if primitive
12501            if (oldValue !== newValue) {
12502              oldValue = newValue;
12503              changeDetected++;
12504            }
12505          } else if (isArrayLike(newValue)) {
12506            if (oldValue !== internalArray) {
12507              // we are transitioning from something which was not an array into array.
12508              oldValue = internalArray;
12509              oldLength = oldValue.length = 0;
12510              changeDetected++;
12511            }
12512
12513            newLength = newValue.length;
12514
12515            if (oldLength !== newLength) {
12516              // if lengths do not match we need to trigger change notification
12517              changeDetected++;
12518              oldValue.length = oldLength = newLength;
12519            }
12520            // copy the items to oldValue and look for changes.
12521            for (var i = 0; i < newLength; i++) {
12522              bothNaN = (oldValue[i] !== oldValue[i]) &&
12523                  (newValue[i] !== newValue[i]);
12524              if (!bothNaN && (oldValue[i] !== newValue[i])) {
12525                changeDetected++;
12526                oldValue[i] = newValue[i];
12527              }
12528            }
12529          } else {
12530            if (oldValue !== internalObject) {
12531              // we are transitioning from something which was not an object into object.
12532              oldValue = internalObject = {};
12533              oldLength = 0;
12534              changeDetected++;
12535            }
12536            // copy the items to oldValue and look for changes.
12537            newLength = 0;
12538            for (key in newValue) {
12539              if (newValue.hasOwnProperty(key)) {
12540                newLength++;
12541                if (oldValue.hasOwnProperty(key)) {
12542                  bothNaN = (oldValue[key] !== oldValue[key]) &&
12543                      (newValue[key] !== newValue[key]);
12544                  if (!bothNaN && (oldValue[key] !== newValue[key])) {
12545                    changeDetected++;
12546                    oldValue[key] = newValue[key];
12547                  }
12548                } else {
12549                  oldLength++;
12550                  oldValue[key] = newValue[key];
12551                  changeDetected++;
12552                }
12553              }
12554            }
12555            if (oldLength > newLength) {
12556              // we used to have more keys, need to find them and destroy them.
12557              changeDetected++;
12558              for(key in oldValue) {
12559                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12560                  oldLength--;
12561                  delete oldValue[key];
12562                }
12563              }
12564            }
12565          }
12566          return changeDetected;
12567        }
12568
12569        function $watchCollectionAction() {
12570          if (initRun) {
12571            initRun = false;
12572            listener(newValue, newValue, self);
12573          } else {
12574            listener(newValue, veryOldValue, self);
12575          }
12576
12577          // make a copy for the next time a collection is changed
12578          if (trackVeryOldValue) {
12579            if (!isObject(newValue)) {
12580              //primitive
12581              veryOldValue = newValue;
12582            } else if (isArrayLike(newValue)) {
12583              veryOldValue = new Array(newValue.length);
12584              for (var i = 0; i < newValue.length; i++) {
12585                veryOldValue[i] = newValue[i];
12586              }
12587            } else { // if object
12588              veryOldValue = {};
12589              for (var key in newValue) {
12590                if (hasOwnProperty.call(newValue, key)) {
12591                  veryOldValue[key] = newValue[key];
12592                }
12593              }
12594            }
12595          }
12596        }
12597
12598        return this.$watch($watchCollectionWatch, $watchCollectionAction);
12599      },
12600
12601      /**
12602       * @ngdoc method
12603       * @name $rootScope.Scope#$digest
12604       * @kind function
12605       *
12606       * @description
12607       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12608       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12609       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12610       * until no more listeners are firing. This means that it is possible to get into an infinite
12611       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12612       * iterations exceeds 10.
12613       *
12614       * Usually, you don't call `$digest()` directly in
12615       * {@link ng.directive:ngController controllers} or in
12616       * {@link ng.$compileProvider#directive directives}.
12617       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12618       * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12619       *
12620       * If you want to be notified whenever `$digest()` is called,
12621       * you can register a `watchExpression` function with
12622       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12623       *
12624       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12625       *
12626       * # Example
12627       * ```js
12628           var scope = ...;
12629           scope.name = 'misko';
12630           scope.counter = 0;
12631
12632           expect(scope.counter).toEqual(0);
12633           scope.$watch('name', function(newValue, oldValue) {
12634             scope.counter = scope.counter + 1;
12635           });
12636           expect(scope.counter).toEqual(0);
12637
12638           scope.$digest();
12639           // the listener is always called during the first $digest loop after it was registered
12640           expect(scope.counter).toEqual(1);
12641
12642           scope.$digest();
12643           // but now it will not be called unless the value changes
12644           expect(scope.counter).toEqual(1);
12645
12646           scope.name = 'adam';
12647           scope.$digest();
12648           expect(scope.counter).toEqual(2);
12649       * ```
12650       *
12651       */
12652      $digest: function() {
12653        var watch, value, last,
12654            watchers,
12655            asyncQueue = this.$$asyncQueue,
12656            postDigestQueue = this.$$postDigestQueue,
12657            length,
12658            dirty, ttl = TTL,
12659            next, current, target = this,
12660            watchLog = [],
12661            logIdx, logMsg, asyncTask;
12662
12663        beginPhase('$digest');
12664        // Check for changes to browser url that happened in sync before the call to $digest
12665        $browser.$$checkUrlChange();
12666
12667        lastDirtyWatch = null;
12668
12669        do { // "while dirty" loop
12670          dirty = false;
12671          current = target;
12672
12673          while(asyncQueue.length) {
12674            try {
12675              asyncTask = asyncQueue.shift();
12676              asyncTask.scope.$eval(asyncTask.expression);
12677            } catch (e) {
12678              clearPhase();
12679              $exceptionHandler(e);
12680            }
12681            lastDirtyWatch = null;
12682          }
12683
12684          traverseScopesLoop:
12685          do { // "traverse the scopes" loop
12686            if ((watchers = current.$$watchers)) {
12687              // process our watches
12688              length = watchers.length;
12689              while (length--) {
12690                try {
12691                  watch = watchers[length];
12692                  // Most common watches are on primitives, in which case we can short
12693                  // circuit it with === operator, only when === fails do we use .equals
12694                  if (watch) {
12695                    if ((value = watch.get(current)) !== (last = watch.last) &&
12696                        !(watch.eq
12697                            ? equals(value, last)
12698                            : (typeof value === 'number' && typeof last === 'number'
12699                               && isNaN(value) && isNaN(last)))) {
12700                      dirty = true;
12701                      lastDirtyWatch = watch;
12702                      watch.last = watch.eq ? copy(value, null) : value;
12703                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
12704                      if (ttl < 5) {
12705                        logIdx = 4 - ttl;
12706                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
12707                        logMsg = (isFunction(watch.exp))
12708                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12709                            : watch.exp;
12710                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12711                        watchLog[logIdx].push(logMsg);
12712                      }
12713                    } else if (watch === lastDirtyWatch) {
12714                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12715                      // have already been tested.
12716                      dirty = false;
12717                      break traverseScopesLoop;
12718                    }
12719                  }
12720                } catch (e) {
12721                  clearPhase();
12722                  $exceptionHandler(e);
12723                }
12724              }
12725            }
12726
12727            // Insanity Warning: scope depth-first traversal
12728            // yes, this code is a bit crazy, but it works and we have tests to prove it!
12729            // this piece should be kept in sync with the traversal in $broadcast
12730            if (!(next = (current.$$childHead ||
12731                (current !== target && current.$$nextSibling)))) {
12732              while(current !== target && !(next = current.$$nextSibling)) {
12733                current = current.$parent;
12734              }
12735            }
12736          } while ((current = next));
12737
12738          // `break traverseScopesLoop;` takes us to here
12739
12740          if((dirty || asyncQueue.length) && !(ttl--)) {
12741            clearPhase();
12742            throw $rootScopeMinErr('infdig',
12743                '{0} $digest() iterations reached. Aborting!\n' +
12744                'Watchers fired in the last 5 iterations: {1}',
12745                TTL, toJson(watchLog));
12746          }
12747
12748        } while (dirty || asyncQueue.length);
12749
12750        clearPhase();
12751
12752        while(postDigestQueue.length) {
12753          try {
12754            postDigestQueue.shift()();
12755          } catch (e) {
12756            $exceptionHandler(e);
12757          }
12758        }
12759      },
12760
12761
12762      /**
12763       * @ngdoc event
12764       * @name $rootScope.Scope#$destroy
12765       * @eventType broadcast on scope being destroyed
12766       *
12767       * @description
12768       * Broadcasted when a scope and its children are being destroyed.
12769       *
12770       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12771       * clean up DOM bindings before an element is removed from the DOM.
12772       */
12773
12774      /**
12775       * @ngdoc method
12776       * @name $rootScope.Scope#$destroy
12777       * @kind function
12778       *
12779       * @description
12780       * Removes the current scope (and all of its children) from the parent scope. Removal implies
12781       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12782       * propagate to the current scope and its children. Removal also implies that the current
12783       * scope is eligible for garbage collection.
12784       *
12785       * The `$destroy()` is usually used by directives such as
12786       * {@link ng.directive:ngRepeat ngRepeat} for managing the
12787       * unrolling of the loop.
12788       *
12789       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12790       * Application code can register a `$destroy` event handler that will give it a chance to
12791       * perform any necessary cleanup.
12792       *
12793       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12794       * clean up DOM bindings before an element is removed from the DOM.
12795       */
12796      $destroy: function() {
12797        // we can't destroy the root scope or a scope that has been already destroyed
12798        if (this.$$destroyed) return;
12799        var parent = this.$parent;
12800
12801        this.$broadcast('$destroy');
12802        this.$$destroyed = true;
12803        if (this === $rootScope) return;
12804
12805        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12806
12807        // sever all the references to parent scopes (after this cleanup, the current scope should
12808        // not be retained by any of our references and should be eligible for garbage collection)
12809        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12810        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12811        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12812        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12813
12814
12815        // All of the code below is bogus code that works around V8's memory leak via optimized code
12816        // and inline caches.
12817        //
12818        // see:
12819        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12820        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12821        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12822
12823        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12824            this.$$childTail = this.$root = null;
12825
12826        // don't reset these to null in case some async task tries to register a listener/watch/task
12827        this.$$listeners = {};
12828        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12829
12830        // prevent NPEs since these methods have references to properties we nulled out
12831        this.$destroy = this.$digest = this.$apply = noop;
12832        this.$on = this.$watch = function() { return noop; };
12833      },
12834
12835      /**
12836       * @ngdoc method
12837       * @name $rootScope.Scope#$eval
12838       * @kind function
12839       *
12840       * @description
12841       * Executes the `expression` on the current scope and returns the result. Any exceptions in
12842       * the expression are propagated (uncaught). This is useful when evaluating Angular
12843       * expressions.
12844       *
12845       * # Example
12846       * ```js
12847           var scope = ng.$rootScope.Scope();
12848           scope.a = 1;
12849           scope.b = 2;
12850
12851           expect(scope.$eval('a+b')).toEqual(3);
12852           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12853       * ```
12854       *
12855       * @param {(string|function())=} expression An angular expression to be executed.
12856       *
12857       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12858       *    - `function(scope)`: execute the function with the current `scope` parameter.
12859       *
12860       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12861       * @returns {*} The result of evaluating the expression.
12862       */
12863      $eval: function(expr, locals) {
12864        return $parse(expr)(this, locals);
12865      },
12866
12867      /**
12868       * @ngdoc method
12869       * @name $rootScope.Scope#$evalAsync
12870       * @kind function
12871       *
12872       * @description
12873       * Executes the expression on the current scope at a later point in time.
12874       *
12875       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12876       * that:
12877       *
12878       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12879       *     rendering).
12880       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12881       *     `expression` execution.
12882       *
12883       * Any exceptions from the execution of the expression are forwarded to the
12884       * {@link ng.$exceptionHandler $exceptionHandler} service.
12885       *
12886       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12887       * will be scheduled. However, it is encouraged to always call code that changes the model
12888       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12889       *
12890       * @param {(string|function())=} expression An angular expression to be executed.
12891       *
12892       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12893       *    - `function(scope)`: execute the function with the current `scope` parameter.
12894       *
12895       */
12896      $evalAsync: function(expr) {
12897        // if we are outside of an $digest loop and this is the first time we are scheduling async
12898        // task also schedule async auto-flush
12899        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12900          $browser.defer(function() {
12901            if ($rootScope.$$asyncQueue.length) {
12902              $rootScope.$digest();
12903            }
12904          });
12905        }
12906
12907        this.$$asyncQueue.push({scope: this, expression: expr});
12908      },
12909
12910      $$postDigest : function(fn) {
12911        this.$$postDigestQueue.push(fn);
12912      },
12913
12914      /**
12915       * @ngdoc method
12916       * @name $rootScope.Scope#$apply
12917       * @kind function
12918       *
12919       * @description
12920       * `$apply()` is used to execute an expression in angular from outside of the angular
12921       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12922       * Because we are calling into the angular framework we need to perform proper scope life
12923       * cycle of {@link ng.$exceptionHandler exception handling},
12924       * {@link ng.$rootScope.Scope#$digest executing watches}.
12925       *
12926       * ## Life cycle
12927       *
12928       * # Pseudo-Code of `$apply()`
12929       * ```js
12930           function $apply(expr) {
12931             try {
12932               return $eval(expr);
12933             } catch (e) {
12934               $exceptionHandler(e);
12935             } finally {
12936               $root.$digest();
12937             }
12938           }
12939       * ```
12940       *
12941       *
12942       * Scope's `$apply()` method transitions through the following stages:
12943       *
12944       * 1. The {@link guide/expression expression} is executed using the
12945       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12946       * 2. Any exceptions from the execution of the expression are forwarded to the
12947       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12948       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12949       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12950       *
12951       *
12952       * @param {(string|function())=} exp An angular expression to be executed.
12953       *
12954       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12955       *    - `function(scope)`: execute the function with current `scope` parameter.
12956       *
12957       * @returns {*} The result of evaluating the expression.
12958       */
12959      $apply: function(expr) {
12960        try {
12961          beginPhase('$apply');
12962          return this.$eval(expr);
12963        } catch (e) {
12964          $exceptionHandler(e);
12965        } finally {
12966          clearPhase();
12967          try {
12968            $rootScope.$digest();
12969          } catch (e) {
12970            $exceptionHandler(e);
12971            throw e;
12972          }
12973        }
12974      },
12975
12976      /**
12977       * @ngdoc method
12978       * @name $rootScope.Scope#$on
12979       * @kind function
12980       *
12981       * @description
12982       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12983       * discussion of event life cycle.
12984       *
12985       * The event listener function format is: `function(event, args...)`. The `event` object
12986       * passed into the listener has the following attributes:
12987       *
12988       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12989       *     `$broadcast`-ed.
12990       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12991       *   - `name` - `{string}`: name of the event.
12992       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12993       *     further event propagation (available only for events that were `$emit`-ed).
12994       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12995       *     to true.
12996       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12997       *
12998       * @param {string} name Event name to listen on.
12999       * @param {function(event, ...args)} listener Function to call when the event is emitted.
13000       * @returns {function()} Returns a deregistration function for this listener.
13001       */
13002      $on: function(name, listener) {
13003        var namedListeners = this.$$listeners[name];
13004        if (!namedListeners) {
13005          this.$$listeners[name] = namedListeners = [];
13006        }
13007        namedListeners.push(listener);
13008
13009        var current = this;
13010        do {
13011          if (!current.$$listenerCount[name]) {
13012            current.$$listenerCount[name] = 0;
13013          }
13014          current.$$listenerCount[name]++;
13015        } while ((current = current.$parent));
13016
13017        var self = this;
13018        return function() {
13019          var indexOfListener = indexOf(namedListeners, listener);
13020          if (indexOfListener !== -1) {
13021            namedListeners[indexOfListener] = null;
13022            decrementListenerCount(self, 1, name);
13023          }
13024        };
13025      },
13026
13027
13028      /**
13029       * @ngdoc method
13030       * @name $rootScope.Scope#$emit
13031       * @kind function
13032       *
13033       * @description
13034       * Dispatches an event `name` upwards through the scope hierarchy notifying the
13035       * registered {@link ng.$rootScope.Scope#$on} listeners.
13036       *
13037       * The event life cycle starts at the scope on which `$emit` was called. All
13038       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
13039       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
13040       * registered listeners along the way. The event will stop propagating if one of the listeners
13041       * cancels it.
13042       *
13043       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
13044       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
13045       *
13046       * @param {string} name Event name to emit.
13047       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
13048       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
13049       */
13050      $emit: function(name, args) {
13051        var empty = [],
13052            namedListeners,
13053            scope = this,
13054            stopPropagation = false,
13055            event = {
13056              name: name,
13057              targetScope: scope,
13058              stopPropagation: function() {stopPropagation = true;},
13059              preventDefault: function() {
13060                event.defaultPrevented = true;
13061              },
13062              defaultPrevented: false
13063            },
13064            listenerArgs = concat([event], arguments, 1),
13065            i, length;
13066
13067        do {
13068          namedListeners = scope.$$listeners[name] || empty;
13069          event.currentScope = scope;
13070          for (i=0, length=namedListeners.length; i<length; i++) {
13071
13072            // if listeners were deregistered, defragment the array
13073            if (!namedListeners[i]) {
13074              namedListeners.splice(i, 1);
13075              i--;
13076              length--;
13077              continue;
13078            }
13079            try {
13080              //allow all listeners attached to the current scope to run
13081              namedListeners[i].apply(null, listenerArgs);
13082            } catch (e) {
13083              $exceptionHandler(e);
13084            }
13085          }
13086          //if any listener on the current scope stops propagation, prevent bubbling
13087          if (stopPropagation) return event;
13088          //traverse upwards
13089          scope = scope.$parent;
13090        } while (scope);
13091
13092        return event;
13093      },
13094
13095
13096      /**
13097       * @ngdoc method
13098       * @name $rootScope.Scope#$broadcast
13099       * @kind function
13100       *
13101       * @description
13102       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
13103       * registered {@link ng.$rootScope.Scope#$on} listeners.
13104       *
13105       * The event life cycle starts at the scope on which `$broadcast` was called. All
13106       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
13107       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
13108       * scope and calls all registered listeners along the way. The event cannot be canceled.
13109       *
13110       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
13111       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
13112       *
13113       * @param {string} name Event name to broadcast.
13114       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
13115       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
13116       */
13117      $broadcast: function(name, args) {
13118        var target = this,
13119            current = target,
13120            next = target,
13121            event = {
13122              name: name,
13123              targetScope: target,
13124              preventDefault: function() {
13125                event.defaultPrevented = true;
13126              },
13127              defaultPrevented: false
13128            },
13129            listenerArgs = concat([event], arguments, 1),
13130            listeners, i, length;
13131
13132        //down while you can, then up and next sibling or up and next sibling until back at root
13133        while ((current = next)) {
13134          event.currentScope = current;
13135          listeners = current.$$listeners[name] || [];
13136          for (i=0, length = listeners.length; i<length; i++) {
13137            // if listeners were deregistered, defragment the array
13138            if (!listeners[i]) {
13139              listeners.splice(i, 1);
13140              i--;
13141              length--;
13142              continue;
13143            }
13144
13145            try {
13146              listeners[i].apply(null, listenerArgs);
13147            } catch(e) {
13148              $exceptionHandler(e);
13149            }
13150          }
13151
13152          // Insanity Warning: scope depth-first traversal
13153          // yes, this code is a bit crazy, but it works and we have tests to prove it!
13154          // this piece should be kept in sync with the traversal in $digest
13155          // (though it differs due to having the extra check for $$listenerCount)
13156          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
13157              (current !== target && current.$$nextSibling)))) {
13158            while(current !== target && !(next = current.$$nextSibling)) {
13159              current = current.$parent;
13160            }
13161          }
13162        }
13163
13164        return event;
13165      }
13166    };
13167
13168    var $rootScope = new Scope();
13169
13170    return $rootScope;
13171
13172
13173    function beginPhase(phase) {
13174      if ($rootScope.$$phase) {
13175        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
13176      }
13177
13178      $rootScope.$$phase = phase;
13179    }
13180
13181    function clearPhase() {
13182      $rootScope.$$phase = null;
13183    }
13184
13185    function compileToFn(exp, name) {
13186      var fn = $parse(exp);
13187      assertArgFn(fn, name);
13188      return fn;
13189    }
13190
13191    function decrementListenerCount(current, count, name) {
13192      do {
13193        current.$$listenerCount[name] -= count;
13194
13195        if (current.$$listenerCount[name] === 0) {
13196          delete current.$$listenerCount[name];
13197        }
13198      } while ((current = current.$parent));
13199    }
13200
13201    /**
13202     * function used as an initial value for watchers.
13203     * because it's unique we can easily tell it apart from other values
13204     */
13205    function initWatchVal() {}
13206  }];
13207}
13208
13209/**
13210 * @ngdoc service
13211 * @name $rootElement
13212 *
13213 * @description
13214 * The root element of Angular application. This is either the element where {@link
13215 * ng.directive:ngApp ngApp} was declared or the element passed into
13216 * {@link angular.bootstrap}. The element represent the root element of application. It is also the
13217 * location where the applications {@link auto.$injector $injector} service gets
13218 * published, it can be retrieved using `$rootElement.injector()`.
13219 */
13220
13221
13222// the implementation is in angular.bootstrap
13223
13224/**
13225 * @description
13226 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
13227 */
13228function $$SanitizeUriProvider() {
13229  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
13230    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
13231
13232  /**
13233   * @description
13234   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13235   * urls during a[href] sanitization.
13236   *
13237   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13238   *
13239   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
13240   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
13241   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
13242   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13243   *
13244   * @param {RegExp=} regexp New regexp to whitelist urls with.
13245   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13246   *    chaining otherwise.
13247   */
13248  this.aHrefSanitizationWhitelist = function(regexp) {
13249    if (isDefined(regexp)) {
13250      aHrefSanitizationWhitelist = regexp;
13251      return this;
13252    }
13253    return aHrefSanitizationWhitelist;
13254  };
13255
13256
13257  /**
13258   * @description
13259   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
13260   * urls during img[src] sanitization.
13261   *
13262   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
13263   *
13264   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
13265   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
13266   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
13267   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
13268   *
13269   * @param {RegExp=} regexp New regexp to whitelist urls with.
13270   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
13271   *    chaining otherwise.
13272   */
13273  this.imgSrcSanitizationWhitelist = function(regexp) {
13274    if (isDefined(regexp)) {
13275      imgSrcSanitizationWhitelist = regexp;
13276      return this;
13277    }
13278    return imgSrcSanitizationWhitelist;
13279  };
13280
13281  this.$get = function() {
13282    return function sanitizeUri(uri, isImage) {
13283      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
13284      var normalizedVal;
13285      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
13286      if (!msie || msie >= 8 ) {
13287        normalizedVal = urlResolve(uri).href;
13288        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
13289          return 'unsafe:'+normalizedVal;
13290        }
13291      }
13292      return uri;
13293    };
13294  };
13295}
13296
13297var $sceMinErr = minErr('$sce');
13298
13299var SCE_CONTEXTS = {
13300  HTML: 'html',
13301  CSS: 'css',
13302  URL: 'url',
13303  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
13304  // url.  (e.g. ng-include, script src, templateUrl)
13305  RESOURCE_URL: 'resourceUrl',
13306  JS: 'js'
13307};
13308
13309// Helper functions follow.
13310
13311// Copied from:
13312// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
13313// Prereq: s is a string.
13314function escapeForRegexp(s) {
13315  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
13316           replace(/\x08/g, '\\x08');
13317}
13318
13319
13320function adjustMatcher(matcher) {
13321  if (matcher === 'self') {
13322    return matcher;
13323  } else if (isString(matcher)) {
13324    // Strings match exactly except for 2 wildcards - '*' and '**'.
13325    // '*' matches any character except those from the set ':/.?&'.
13326    // '**' matches any character (like .* in a RegExp).
13327    // More than 2 *'s raises an error as it's ill defined.
13328    if (matcher.indexOf('***') > -1) {
13329      throw $sceMinErr('iwcard',
13330          'Illegal sequence *** in string matcher.  String: {0}', matcher);
13331    }
13332    matcher = escapeForRegexp(matcher).
13333                  replace('\\*\\*', '.*').
13334                  replace('\\*', '[^:/.?&;]*');
13335    return new RegExp('^' + matcher + '$');
13336  } else if (isRegExp(matcher)) {
13337    // The only other type of matcher allowed is a Regexp.
13338    // Match entire URL / disallow partial matches.
13339    // Flags are reset (i.e. no global, ignoreCase or multiline)
13340    return new RegExp('^' + matcher.source + '$');
13341  } else {
13342    throw $sceMinErr('imatcher',
13343        'Matchers may only be "self", string patterns or RegExp objects');
13344  }
13345}
13346
13347
13348function adjustMatchers(matchers) {
13349  var adjustedMatchers = [];
13350  if (isDefined(matchers)) {
13351    forEach(matchers, function(matcher) {
13352      adjustedMatchers.push(adjustMatcher(matcher));
13353    });
13354  }
13355  return adjustedMatchers;
13356}
13357
13358
13359/**
13360 * @ngdoc service
13361 * @name $sceDelegate
13362 * @kind function
13363 *
13364 * @description
13365 *
13366 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
13367 * Contextual Escaping (SCE)} services to AngularJS.
13368 *
13369 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
13370 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
13371 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
13372 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
13373 * work because `$sce` delegates to `$sceDelegate` for these operations.
13374 *
13375 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
13376 *
13377 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
13378 * can override it completely to change the behavior of `$sce`, the common case would
13379 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
13380 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
13381 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
13382 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
13383 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13384 */
13385
13386/**
13387 * @ngdoc provider
13388 * @name $sceDelegateProvider
13389 * @description
13390 *
13391 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
13392 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
13393 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
13394 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
13395 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13396 *
13397 * For the general details about this service in Angular, read the main page for {@link ng.$sce
13398 * Strict Contextual Escaping (SCE)}.
13399 *
13400 * **Example**:  Consider the following case. <a name="example"></a>
13401 *
13402 * - your app is hosted at url `http://myapp.example.com/`
13403 * - but some of your templates are hosted on other domains you control such as
13404 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
13405 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
13406 *
13407 * Here is what a secure configuration for this scenario might look like:
13408 *
13409 * ```
13410 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
13411 *    $sceDelegateProvider.resourceUrlWhitelist([
13412 *      // Allow same origin resource loads.
13413 *      'self',
13414 *      // Allow loading from our assets domain.  Notice the difference between * and **.
13415 *      'http://srv*.assets.example.com/**'
13416 *    ]);
13417 *
13418 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
13419 *    $sceDelegateProvider.resourceUrlBlacklist([
13420 *      'http://myapp.example.com/clickThru**'
13421 *    ]);
13422 *  });
13423 * ```
13424 */
13425
13426function $SceDelegateProvider() {
13427  this.SCE_CONTEXTS = SCE_CONTEXTS;
13428
13429  // Resource URLs can also be trusted by policy.
13430  var resourceUrlWhitelist = ['self'],
13431      resourceUrlBlacklist = [];
13432
13433  /**
13434   * @ngdoc method
13435   * @name $sceDelegateProvider#resourceUrlWhitelist
13436   * @kind function
13437   *
13438   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
13439   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13440   *     changes to the array are ignored.
13441   *
13442   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13443   *     allowed in this array.
vendor: 4,150 bytes, lines 13444-13568
13444   *
13445   *     Note: **an empty whitelist array will block all URLs**!
13446   *
13447   * @return {Array} the currently set whitelist array.
13448   *
13449   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
13450   * same origin resource requests.
13451   *
13452   * @description
13453   * Sets/Gets the whitelist of trusted resource URLs.
13454   */
13455  this.resourceUrlWhitelist = function (value) {
13456    if (arguments.length) {
13457      resourceUrlWhitelist = adjustMatchers(value);
13458    }
13459    return resourceUrlWhitelist;
13460  };
13461
13462  /**
13463   * @ngdoc method
13464   * @name $sceDelegateProvider#resourceUrlBlacklist
13465   * @kind function
13466   *
13467   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
13468   *     provided.  This must be an array or null.  A snapshot of this array is used so further
13469   *     changes to the array are ignored.
13470   *
13471   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13472   *     allowed in this array.
13473   *
13474   *     The typical usage for the blacklist is to **block
13475   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13476   *     these would otherwise be trusted but actually return content from the redirected domain.
13477   *
13478   *     Finally, **the blacklist overrides the whitelist** and has the final say.
13479   *
13480   * @return {Array} the currently set blacklist array.
13481   *
13482   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13483   * is no blacklist.)
13484   *
13485   * @description
13486   * Sets/Gets the blacklist of trusted resource URLs.
13487   */
13488
13489  this.resourceUrlBlacklist = function (value) {
13490    if (arguments.length) {
13491      resourceUrlBlacklist = adjustMatchers(value);
13492    }
13493    return resourceUrlBlacklist;
13494  };
13495
13496  this.$get = ['$injector', function($injector) {
13497
13498    var htmlSanitizer = function htmlSanitizer(html) {
13499      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13500    };
13501
13502    if ($injector.has('$sanitize')) {
13503      htmlSanitizer = $injector.get('$sanitize');
13504    }
13505
13506
13507    function matchUrl(matcher, parsedUrl) {
13508      if (matcher === 'self') {
13509        return urlIsSameOrigin(parsedUrl);
13510      } else {
13511        // definitely a regex.  See adjustMatchers()
13512        return !!matcher.exec(parsedUrl.href);
13513      }
13514    }
13515
13516    function isResourceUrlAllowedByPolicy(url) {
13517      var parsedUrl = urlResolve(url.toString());
13518      var i, n, allowed = false;
13519      // Ensure that at least one item from the whitelist allows this url.
13520      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13521        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13522          allowed = true;
13523          break;
13524        }
13525      }
13526      if (allowed) {
13527        // Ensure that no item from the blacklist blocked this url.
13528        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13529          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13530            allowed = false;
13531            break;
13532          }
13533        }
13534      }
13535      return allowed;
13536    }
13537
13538    function generateHolderType(Base) {
13539      var holderType = function TrustedValueHolderType(trustedValue) {
13540        this.$$unwrapTrustedValue = function() {
13541          return trustedValue;
13542        };
13543      };
13544      if (Base) {
13545        holderType.prototype = new Base();
13546      }
13547      holderType.prototype.valueOf = function sceValueOf() {
13548        return this.$$unwrapTrustedValue();
13549      };
13550      holderType.prototype.toString = function sceToString() {
13551        return this.$$unwrapTrustedValue().toString();
13552      };
13553      return holderType;
13554    }
13555
13556    var trustedValueHolderBase = generateHolderType(),
13557        byType = {};
13558
13559    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13560    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13561    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13562    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13563    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13564
13565    /**
13566     * @ngdoc method
13567     * @name $sceDelegate#trustAs
13568     *
13569     * @description
13570     * Returns an object that is trusted by angular for use in specified strict
13571     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13572     * attribute interpolation, any dom event binding attribute interpolation
13573     * such as for onclick,  etc.) that uses the provided value.
13574     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13575     *
13576     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13577     *   resourceUrl, html, js and css.
13578     * @param {*} value The value that that should be considered trusted/safe.
13579     * @returns {*} A value that can be used to stand in for the provided `value` in places
13580     * where Angular expects a $sce.trustAs() return value.
13581     */
13582    function trustAs(type, trustedValue) {
13583      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13584      if (!Constructor) {
13585        throw $sceMinErr('icontext',
13586            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13587            type, trustedValue);
13588      }
13589      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13590        return trustedValue;
13591      }
13592      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13593      // mutable objects, we ensure here that the value passed in is actually a string.
13594      if (typeof trustedValue !== 'string') {
13595        throw $sceMinErr('itype',
13596            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13597            type);
13598      }
13599      return new Constructor(trustedValue);
13600    }
13601
13602    /**
13603     * @ngdoc method
13604     * @name $sceDelegate#valueOf
13605     *
13606     * @description
13607     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13608     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13609     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13610     *
13611     * If the passed parameter is not a value that had been returned by {@link
13612     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13613     *
13614     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13615     *      call or anything else.
13616     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13617     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13618     *     `value` unchanged.
13619     */
13620    function valueOf(maybeTrusted) {
13621      if (maybeTrusted instanceof trustedValueHolderBase) {
13622        return maybeTrusted.$$unwrapTrustedValue();
13623      } else {
13624        return maybeTrusted;
13625      }
13626    }
13627
13628    /**
13629     * @ngdoc method
13630     * @name $sceDelegate#getTrusted
13631     *
13632     * @description
13633     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13634     * returns the originally supplied value if the queried context type is a supertype of the
13635     * created type.  If this condition isn't satisfied, throws an exception.
13636     *
13637     * @param {string} type The kind of context in which this value is to be used.
13638     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13639     *     `$sceDelegate.trustAs`} call.
13640     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13641     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13642     */
13643    function getTrusted(type, maybeTrusted) {
13644      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13645        return maybeTrusted;
13646      }
13647      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13648      if (constructor && maybeTrusted instanceof constructor) {
13649        return maybeTrusted.$$unwrapTrustedValue();
13650      }
13651      // If we get here, then we may only take one of two actions.
13652      // 1. sanitize the value for the requested type, or
13653      // 2. throw an exception.
13654      if (type === SCE_CONTEXTS.RESOURCE_URL) {
13655        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13656          return maybeTrusted;
13657        } else {
13658          throw $sceMinErr('insecurl',
13659              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13660              maybeTrusted.toString());
13661        }
13662      } else if (type === SCE_CONTEXTS.HTML) {
13663        return htmlSanitizer(maybeTrusted);
13664      }
13665      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13666    }
13667
13668    return { trustAs: trustAs,
13669             getTrusted: getTrusted,
13670             valueOf: valueOf };
13671  }];
13672}
13673
13674
13675/**
13676 * @ngdoc provider
13677 * @name $sceProvider
13678 * @description
13679 *
13680 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13681 * -   enable/disable Strict Contextual Escaping (SCE) in a module
13682 * -   override the default implementation with a custom delegate
13683 *
13684 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13685 */
13686
13687/* jshint maxlen: false*/
13688
13689/**
13690 * @ngdoc service
13691 * @name $sce
13692 * @kind function
13693 *
13694 * @description
13695 *
13696 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13697 *
13698 * # Strict Contextual Escaping
13699 *
13700 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13701 * contexts to result in a value that is marked as safe to use for that context.  One example of
13702 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13703 * to these contexts as privileged or SCE contexts.
13704 *
13705 * As of version 1.2, Angular ships with SCE enabled by default.
13706 *
13707 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13708 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13709 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13710 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13711 * to the top of your HTML document.
13712 *
13713 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13714 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13715 *
13716 * Here's an example of a binding in a privileged context:
13717 *
13718 * ```
13719 * <input ng-model="userHtml">
13720 * <div ng-bind-html="userHtml"></div>
13721 * ```
13722 *
13723 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13724 * disabled, this application allows the user to render arbitrary HTML into the DIV.
13725 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13726 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13727 * security vulnerabilities.)
13728 *
13729 * For the case of HTML, you might use a library, either on the client side, or on the server side,
13730 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13731 *
13732 * How would you ensure that every place that used these types of bindings was bound to a value that
13733 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13734 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13735 * properties/fields and forgot to update the binding to the sanitized value?
13736 *
13737 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13738 * determine that something explicitly says it's safe to use a value for binding in that
13739 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13740 * for those values that you can easily tell are safe - because they were received from your server,
13741 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13742 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13743 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13744 *
13745 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13746 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13747 * obtain values that will be accepted by SCE / privileged contexts.
13748 *
13749 *
13750 * ## How does it work?
13751 *
13752 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13753 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13754 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13755 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13756 *
13757 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13758 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13759 * simplified):
13760 *
13761 * ```
13762 * var ngBindHtmlDirective = ['$sce', function($sce) {
13763 *   return function(scope, element, attr) {
13764 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13765 *       element.html(value || '');
13766 *     });
13767 *   };
13768 * }];
13769 * ```
13770 *
13771 * ## Impact on loading templates
13772 *
13773 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13774 * `templateUrl`'s specified by {@link guide/directive directives}.
13775 *
13776 * By default, Angular only loads templates from the same domain and protocol as the application
13777 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13778 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13779 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13780 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13781 *
13782 * *Please note*:
13783 * The browser's
13784 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13785 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13786 * policy apply in addition to this and may further restrict whether the template is successfully
13787 * loaded.  This means that without the right CORS policy, loading templates from a different domain
13788 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13789 * browsers.
13790 *
13791 * ## This feels like too much overhead for the developer?
13792 *
13793 * It's important to remember that SCE only applies to interpolation expressions.
13794 *
13795 * If your expressions are constant literals, they're automatically trusted and you don't need to
13796 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13797 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13798 *
13799 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13800 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13801 *
13802 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13803 * templates in `ng-include` from your application's domain without having to even know about SCE.
13804 * It blocks loading templates from other domains or loading templates over http from an https
13805 * served document.  You can change these by setting your own custom {@link
13806 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13807 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13808 *
13809 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13810 * application that's secure and can be audited to verify that with much more ease than bolting
13811 * security onto an application later.
13812 *
13813 * <a name="contexts"></a>
13814 * ## What trusted context types are supported?
13815 *
13816 * | Context             | Notes          |
13817 * |---------------------|----------------|
13818 * | `$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. |
13819 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13820 * | `$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. |
13821 * | `$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. |
13822 * | `$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. |
13823 *
13824 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13825 *
13826 *  Each element in these arrays must be one of the following:
13827 *
13828 *  - **'self'**
13829 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13830 *      domain** as the application document using the **same protocol**.
13831 *  - **String** (except the special value `'self'`)
13832 *    - The string is matched against the full *normalized / absolute URL* of the resource
13833 *      being tested (substring matches are not good enough.)
13834 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13835 *      match themselves.
13836 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13837 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13838 *      in a whitelist.
13839 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13840 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13841 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13842 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
13843 *      http://foo.example.com/templates/**).
13844 *  - **RegExp** (*see caveat below*)
13845 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13846 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13847 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13848 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13849 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13850 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13851 *      is highly recommended to use the string patterns and only fall back to regular expressions
13852 *      if they as a last resort.
13853 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13854 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13855 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13856 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13857 *    - If you are generating your JavaScript from some other templating engine (not
13858 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13859 *      remember to escape your regular expression (and be aware that you might need more than
13860 *      one level of escaping depending on your templating engine and the way you interpolated
13861 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13862 *      enough before coding your own.  e.g. Ruby has
13863 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13864 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13865 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13866 *      Closure library's [goog.string.regExpEscape(s)](
13867 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13868 *
13869 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13870 *
13871 * ## Show me an example using SCE.
13872 *
13873 * <example module="mySceApp" deps="angular-sanitize.js">
13874 * <file name="index.html">
13875 *   <div ng-controller="myAppController as myCtrl">
13876 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13877 *     <b>User comments</b><br>
13878 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13879 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13880 *     exploit.
13881 *     <div class="well">
13882 *       <div ng-repeat="userComment in myCtrl.userComments">
13883 *         <b>{{userComment.name}}</b>:
13884 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13885 *         <br>
13886 *       </div>
13887 *     </div>
13888 *   </div>
13889 * </file>
13890 *
13891 * <file name="script.js">
13892 *   var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13893 *
13894 *   mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13895 *     var self = this;
13896 *     $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13897 *       self.userComments = userComments;
13898 *     });
13899 *     self.explicitlyTrustedHtml = $sce.trustAsHtml(
13900 *         '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13901 *         'sanitization.&quot;">Hover over this text.</span>');
13902 *   });
13903 * </file>
13904 *
13905 * <file name="test_data.json">
13906 * [
13907 *   { "name": "Alice",
13908 *     "htmlComment":
13909 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13910 *   },
13911 *   { "name": "Bob",
13912 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13913 *   }
13914 * ]
13915 * </file>
13916 *
13917 * <file name="protractor.js" type="protractor">
13918 *   describe('SCE doc demo', function() {
13919 *     it('should sanitize untrusted values', function() {
13920 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
13921 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
13922 *     });
13923 *
13924 *     it('should NOT sanitize explicitly trusted values', function() {
13925 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13926 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13927 *           'sanitization.&quot;">Hover over this text.</span>');
13928 *     });
13929 *   });
13930 * </file>
13931 * </example>
13932 *
13933 *
13934 *
13935 * ## Can I disable SCE completely?
13936 *
13937 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13938 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13939 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13940 * for cases where you have a lot of existing code that was written before SCE was introduced and
13941 * you're migrating them a module at a time.
13942 *
13943 * That said, here's how you can completely disable SCE:
13944 *
13945 * ```
13946 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13947 *   // Completely disable SCE.  For demonstration purposes only!
13948 *   // Do not use in new projects.
13949 *   $sceProvider.enabled(false);
13950 * });
13951 * ```
13952 *
13953 */
13954/* jshint maxlen: 100 */
13955
13956function $SceProvider() {
13957  var enabled = true;
13958
13959  /**
13960   * @ngdoc method
13961   * @name $sceProvider#enabled
13962   * @kind function
13963   *
13964   * @param {boolean=} value If provided, then enables/disables SCE.
13965   * @return {boolean} true if SCE is enabled, false otherwise.
13966   *
13967   * @description
13968   * Enables/disables SCE and returns the current value.
13969   */
13970  this.enabled = function (value) {
13971    if (arguments.length) {
13972      enabled = !!value;
13973    }
13974    return enabled;
13975  };
13976
13977
13978  /* Design notes on the default implementation for SCE.
13979   *
13980   * The API contract for the SCE delegate
13981   * -------------------------------------
13982   * The SCE delegate object must provide the following 3 methods:
13983   *
13984   * - trustAs(contextEnum, value)
13985   *     This method is used to tell the SCE service that the provided value is OK to use in the
13986   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13987   *     getTrusted() for a compatible contextEnum and return this value.
13988   *
13989   * - valueOf(value)
13990   *     For values that were not produced by trustAs(), return them as is.  For values that were
13991   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13992   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13993   *     such a value.
13994   *
13995   * - getTrusted(contextEnum, value)
13996   *     This function should return the a value that is safe to use in the context specified by
13997   *     contextEnum or throw and exception otherwise.
13998   *
13999   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
14000   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
14001   * instance, an implementation could maintain a registry of all trusted objects by context.  In
14002   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
14003   * return the same object passed in if it was found in the registry under a compatible context or
14004   * throw an exception otherwise.  An implementation might only wrap values some of the time based
14005   * on some criteria.  getTrusted() might return a value and not throw an exception for special
14006   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
14007   *
14008   *
14009   * A note on the inheritance model for SCE contexts
14010   * ------------------------------------------------
14011   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
14012   * is purely an implementation details.
14013   *
14014   * The contract is simply this:
14015   *
14016   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
14017   *     will also succeed.
14018   *
14019   * Inheritance happens to capture this in a natural way.  In some future, we
14020   * may not use inheritance anymore.  That is OK because no code outside of
14021   * sce.js and sceSpecs.js would need to be aware of this detail.
14022   */
14023
14024  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
14025                $parse,   $sniffer,   $sceDelegate) {
14026    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
14027    // the "expression(javascript expression)" syntax which is insecure.
14028    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
14029      throw $sceMinErr('iequirks',
14030        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
14031        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
14032        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
14033    }
14034
14035    var sce = shallowCopy(SCE_CONTEXTS);
14036
14037    /**
14038     * @ngdoc method
14039     * @name $sce#isEnabled
14040     * @kind function
14041     *
14042     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
14043     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
14044     *
14045     * @description
14046     * Returns a boolean indicating if SCE is enabled.
14047     */
14048    sce.isEnabled = function () {
14049      return enabled;
14050    };
14051    sce.trustAs = $sceDelegate.trustAs;
14052    sce.getTrusted = $sceDelegate.getTrusted;
14053    sce.valueOf = $sceDelegate.valueOf;
14054
14055    if (!enabled) {
14056      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
14057      sce.valueOf = identity;
14058    }
14059
14060    /**
14061     * @ngdoc method
14062     * @name $sce#parseAs
14063     *
14064     * @description
14065     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
14066     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
14067     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
14068     * *result*)}
14069     *
14070     * @param {string} type The kind of SCE context in which this result will be used.
14071     * @param {string} expression String expression to compile.
14072     * @returns {function(context, locals)} a function which represents the compiled expression:
14073     *
14074     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14075     *      are evaluated against (typically a scope object).
14076     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14077     *      `context`.
14078     */
14079    sce.parseAs = function sceParseAs(type, expr) {
14080      var parsed = $parse(expr);
14081      if (parsed.literal && parsed.constant) {
14082        return parsed;
14083      } else {
14084        return function sceParseAsTrusted(self, locals) {
14085          return sce.getTrusted(type, parsed(self, locals));
14086        };
14087      }
14088    };
14089
14090    /**
14091     * @ngdoc method
14092     * @name $sce#trustAs
14093     *
14094     * @description
14095     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
14096     * returns an object that is trusted by angular for use in specified strict contextual
14097     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
14098     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
14099     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
14100     * escaping.
14101     *
14102     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
14103     *   resource_url, html, js and css.
14104     * @param {*} value The value that that should be considered trusted/safe.
14105     * @returns {*} A value that can be used to stand in for the provided `value` in places
14106     * where Angular expects a $sce.trustAs() return value.
14107     */
14108
14109    /**
14110     * @ngdoc method
14111     * @name $sce#trustAsHtml
14112     *
14113     * @description
14114     * Shorthand method.  `$sce.trustAsHtml(value)` →
14115     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
14116     *
14117     * @param {*} value The value to trustAs.
14118     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
14119     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
14120     *     only accept expressions that are either literal constants or are the
14121     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
14122     */
14123
14124    /**
14125     * @ngdoc method
14126     * @name $sce#trustAsUrl
14127     *
14128     * @description
14129     * Shorthand method.  `$sce.trustAsUrl(value)` →
14130     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
14131     *
14132     * @param {*} value The value to trustAs.
14133     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
14134     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
14135     *     only accept expressions that are either literal constants or are the
14136     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
14137     */
14138
14139    /**
14140     * @ngdoc method
14141     * @name $sce#trustAsResourceUrl
14142     *
14143     * @description
14144     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
14145     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
14146     *
14147     * @param {*} value The value to trustAs.
14148     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
14149     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
14150     *     only accept expressions that are either literal constants or are the return
14151     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
14152     */
14153
14154    /**
14155     * @ngdoc method
14156     * @name $sce#trustAsJs
14157     *
14158     * @description
14159     * Shorthand method.  `$sce.trustAsJs(value)` →
14160     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
14161     *
14162     * @param {*} value The value to trustAs.
14163     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
14164     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
14165     *     only accept expressions that are either literal constants or are the
14166     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
14167     */
14168
14169    /**
14170     * @ngdoc method
14171     * @name $sce#getTrusted
14172     *
14173     * @description
14174     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
14175     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
14176     * originally supplied value if the queried context type is a supertype of the created type.
14177     * If this condition isn't satisfied, throws an exception.
14178     *
14179     * @param {string} type The kind of context in which this value is to be used.
14180     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
14181     *                         call.
14182     * @returns {*} The value the was originally provided to
14183     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
14184     *              Otherwise, throws an exception.
14185     */
14186
14187    /**
14188     * @ngdoc method
14189     * @name $sce#getTrustedHtml
14190     *
14191     * @description
14192     * Shorthand method.  `$sce.getTrustedHtml(value)` →
14193     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
14194     *
14195     * @param {*} value The value to pass to `$sce.getTrusted`.
14196     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
14197     */
14198
14199    /**
14200     * @ngdoc method
14201     * @name $sce#getTrustedCss
14202     *
14203     * @description
14204     * Shorthand method.  `$sce.getTrustedCss(value)` →
14205     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
14206     *
14207     * @param {*} value The value to pass to `$sce.getTrusted`.
14208     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
14209     */
14210
14211    /**
14212     * @ngdoc method
14213     * @name $sce#getTrustedUrl
14214     *
14215     * @description
14216     * Shorthand method.  `$sce.getTrustedUrl(value)` →
14217     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
14218     *
14219     * @param {*} value The value to pass to `$sce.getTrusted`.
14220     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
14221     */
14222
14223    /**
14224     * @ngdoc method
14225     * @name $sce#getTrustedResourceUrl
14226     *
14227     * @description
14228     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
14229     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
14230     *
14231     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
14232     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
14233     */
14234
14235    /**
14236     * @ngdoc method
14237     * @name $sce#getTrustedJs
14238     *
14239     * @description
14240     * Shorthand method.  `$sce.getTrustedJs(value)` →
14241     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
14242     *
14243     * @param {*} value The value to pass to `$sce.getTrusted`.
14244     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
14245     */
14246
14247    /**
14248     * @ngdoc method
14249     * @name $sce#parseAsHtml
14250     *
14251     * @description
14252     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
14253     *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
14254     *
14255     * @param {string} expression String expression to compile.
14256     * @returns {function(context, locals)} a function which represents the compiled expression:
14257     *
14258     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14259     *      are evaluated against (typically a scope object).
14260     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14261     *      `context`.
14262     */
14263
14264    /**
14265     * @ngdoc method
14266     * @name $sce#parseAsCss
14267     *
14268     * @description
14269     * Shorthand method.  `$sce.parseAsCss(value)` →
14270     *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
14271     *
14272     * @param {string} expression String expression to compile.
14273     * @returns {function(context, locals)} a function which represents the compiled expression:
14274     *
14275     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14276     *      are evaluated against (typically a scope object).
14277     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14278     *      `context`.
14279     */
14280
14281    /**
14282     * @ngdoc method
14283     * @name $sce#parseAsUrl
14284     *
14285     * @description
14286     * Shorthand method.  `$sce.parseAsUrl(value)` →
14287     *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
14288     *
14289     * @param {string} expression String expression to compile.
14290     * @returns {function(context, locals)} a function which represents the compiled expression:
14291     *
14292     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14293     *      are evaluated against (typically a scope object).
14294     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14295     *      `context`.
14296     */
14297
14298    /**
14299     * @ngdoc method
14300     * @name $sce#parseAsResourceUrl
14301     *
14302     * @description
14303     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
14304     *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
14305     *
14306     * @param {string} expression String expression to compile.
14307     * @returns {function(context, locals)} a function which represents the compiled expression:
14308     *
14309     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14310     *      are evaluated against (typically a scope object).
14311     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14312     *      `context`.
14313     */
14314
14315    /**
14316     * @ngdoc method
14317     * @name $sce#parseAsJs
14318     *
14319     * @description
14320     * Shorthand method.  `$sce.parseAsJs(value)` →
14321     *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
14322     *
14323     * @param {string} expression String expression to compile.
14324     * @returns {function(context, locals)} a function which represents the compiled expression:
14325     *
14326     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
14327     *      are evaluated against (typically a scope object).
14328     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
14329     *      `context`.
14330     */
14331
14332    // Shorthand delegations.
14333    var parse = sce.parseAs,
14334        getTrusted = sce.getTrusted,
14335        trustAs = sce.trustAs;
14336
14337    forEach(SCE_CONTEXTS, function (enumValue, name) {
14338      var lName = lowercase(name);
14339      sce[camelCase("parse_as_" + lName)] = function (expr) {
14340        return parse(enumValue, expr);
14341      };
14342      sce[camelCase("get_trusted_" + lName)] = function (value) {
14343        return getTrusted(enumValue, value);
14344      };
14345      sce[camelCase("trust_as_" + lName)] = function (value) {
14346        return trustAs(enumValue, value);
14347      };
14348    });
14349
14350    return sce;
14351  }];
14352}
14353
14354/**
14355 * !!! This is an undocumented "private" service !!!
14356 *
14357 * @name $sniffer
14358 * @requires $window
14359 * @requires $document
14360 *
14361 * @property {boolean} history Does the browser support html5 history api ?
14362 * @property {boolean} hashchange Does the browser support hashchange event ?
14363 * @property {boolean} transitions Does the browser support CSS transition events ?
14364 * @property {boolean} animations Does the browser support CSS animation events ?
14365 *
14366 * @description
14367 * This is very simple implementation of testing browser's features.
14368 */
14369function $SnifferProvider() {
14370  this.$get = ['$window', '$document', function($window, $document) {
14371    var eventSupport = {},
14372        android =
14373          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
14374        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
14375        document = $document[0] || {},
14376        documentMode = document.documentMode,
14377        vendorPrefix,
14378        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
14379        bodyStyle = document.body && document.body.style,
14380        transitions = false,
14381        animations = false,
14382        match;
14383
14384    if (bodyStyle) {
14385      for(var prop in bodyStyle) {
14386        if(match = vendorRegex.exec(prop)) {
14387          vendorPrefix = match[0];
14388          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
14389          break;
14390        }
14391      }
14392
14393      if(!vendorPrefix) {
14394        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
14395      }
14396
14397      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
14398      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
14399
14400      if (android && (!transitions||!animations)) {
14401        transitions = isString(document.body.style.webkitTransition);
14402        animations = isString(document.body.style.webkitAnimation);
14403      }
14404    }
14405
14406
14407    return {
14408      // Android has history.pushState, but it does not update location correctly
14409      // so let's not use the history API at all.
14410      // http://code.google.com/p/android/issues/detail?id=17471
14411      // https://github.com/angular/angular.js/issues/904
14412
14413      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
14414      // so let's not use the history API also
14415      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
14416      // jshint -W018
14417      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
14418      // jshint +W018
14419      hashchange: 'onhashchange' in $window &&
14420                  // IE8 compatible mode lies
14421                  (!documentMode || documentMode > 7),
14422      hasEvent: function(event) {
14423        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
14424        // it. In particular the event is not fired when backspace or delete key are pressed or
14425        // when cut operation is performed.
14426        if (event == 'input' && msie == 9) return false;
14427
14428        if (isUndefined(eventSupport[event])) {
14429          var divElm = document.createElement('div');
14430          eventSupport[event] = 'on' + event in divElm;
14431        }
14432
14433        return eventSupport[event];
14434      },
14435      csp: csp(),
14436      vendorPrefix: vendorPrefix,
14437      transitions : transitions,
14438      animations : animations,
14439      android: android,
14440      msie : msie,
14441      msieDocumentMode: documentMode
14442    };
14443  }];
14444}
14445
14446function $TimeoutProvider() {
14447  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14448       function($rootScope,   $browser,   $q,   $exceptionHandler) {
14449    var deferreds = {};
14450
14451
14452     /**
14453      * @ngdoc service
14454      * @name $timeout
14455      *
14456      * @description
14457      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
14458      * block and delegates any exceptions to
14459      * {@link ng.$exceptionHandler $exceptionHandler} service.
14460      *
14461      * The return value of registering a timeout function is a promise, which will be resolved when
14462      * the timeout is reached and the timeout function is executed.
14463      *
14464      * To cancel a timeout request, call `$timeout.cancel(promise)`.
14465      *
14466      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
14467      * synchronously flush the queue of deferred functions.
14468      *
14469      * @param {function()} fn A function, whose execution should be delayed.
14470      * @param {number=} [delay=0] Delay in milliseconds.
14471      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14472      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14473      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14474      *   promise will be resolved with is the return value of the `fn` function.
14475      *
14476      */
14477    function timeout(fn, delay, invokeApply) {
14478      var deferred = $q.defer(),
14479          promise = deferred.promise,
14480          skipApply = (isDefined(invokeApply) && !invokeApply),
14481          timeoutId;
14482
14483      timeoutId = $browser.defer(function() {
14484        try {
14485          deferred.resolve(fn());
14486        } catch(e) {
14487          deferred.reject(e);
14488          $exceptionHandler(e);
14489        }
14490        finally {
14491          delete deferreds[promise.$$timeoutId];
14492        }
14493
14494        if (!skipApply) $rootScope.$apply();
14495      }, delay);
14496
14497      promise.$$timeoutId = timeoutId;
14498      deferreds[timeoutId] = deferred;
14499
14500      return promise;
14501    }
14502
14503
14504     /**
14505      * @ngdoc method
14506      * @name $timeout#cancel
14507      *
14508      * @description
14509      * Cancels a task associated with the `promise`. As a result of this, the promise will be
14510      * resolved with a rejection.
14511      *
14512      * @param {Promise=} promise Promise returned by the `$timeout` function.
14513      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14514      *   canceled.
14515      */
14516    timeout.cancel = function(promise) {
14517      if (promise && promise.$$timeoutId in deferreds) {
14518        deferreds[promise.$$timeoutId].reject('canceled');
14519        delete deferreds[promise.$$timeoutId];
14520        return $browser.defer.cancel(promise.$$timeoutId);
14521      }
14522      return false;
14523    };
14524
14525    return timeout;
14526  }];
14527}
14528
14529// NOTE:  The usage of window and document instead of $window and $document here is
14530// deliberate.  This service depends on the specific behavior of anchor nodes created by the
14531// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14532// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14533// doesn't know about mocked locations and resolves URLs to the real document - which is
14534// exactly the behavior needed here.  There is little value is mocking these out for this
14535// service.
14536var urlParsingNode = document.createElement("a");
14537var originUrl = urlResolve(window.location.href, true);
14538
14539
14540/**
14541 *
14542 * Implementation Notes for non-IE browsers
14543 * ----------------------------------------
14544 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14545 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14546 * URL will be resolved into an absolute URL in the context of the application document.
14547 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14548 * properties are all populated to reflect the normalized URL.  This approach has wide
14549 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14550 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14551 *
14552 * Implementation Notes for IE
14553 * ---------------------------
14554 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14555 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14556 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14557 * work around that by performing the parsing in a 2nd step by taking a previously normalized
14558 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14559 * properties such as protocol, hostname, port, etc.
14560 *
14561 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14562 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14563 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14564 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14565 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14566 * method and IE < 8 is unsupported.
14567 *
14568 * References:
14569 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14570 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14571 *   http://url.spec.whatwg.org/#urlutils
14572 *   https://github.com/angular/angular.js/pull/2902
14573 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14574 *
14575 * @kind function
14576 * @param {string} url The URL to be parsed.
14577 * @description Normalizes and parses a URL.
14578 * @returns {object} Returns the normalized URL as a dictionary.
14579 *
14580 *   | member name   | Description    |
14581 *   |---------------|----------------|
14582 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14583 *   | protocol      | The protocol including the trailing colon                              |
14584 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14585 *   | search        | The search params, minus the question mark                             |
14586 *   | hash          | The hash string, minus the hash symbol
14587 *   | hostname      | The hostname
14588 *   | port          | The port, without ":"
14589 *   | pathname      | The pathname, beginning with "/"
14590 *
14591 */
14592function urlResolve(url, base) {
14593  var href = url;
14594
14595  if (msie) {
14596    // Normalize before parse.  Refer Implementation Notes on why this is
14597    // done in two steps on IE.
14598    urlParsingNode.setAttribute("href", href);
14599    href = urlParsingNode.href;
14600  }
14601
14602  urlParsingNode.setAttribute('href', href);
14603
14604  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14605  return {
14606    href: urlParsingNode.href,
14607    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14608    host: urlParsingNode.host,
14609    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14610    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14611    hostname: urlParsingNode.hostname,
14612    port: urlParsingNode.port,
14613    pathname: (urlParsingNode.pathname.charAt(0) === '/')
14614      ? urlParsingNode.pathname
14615      : '/' + urlParsingNode.pathname
14616  };
14617}
14618
14619/**
14620 * Parse a request URL and determine whether this is a same-origin request as the application document.
14621 *
14622 * @param {string|object} requestUrl The url of the request as a string that will be resolved
14623 * or a parsed URL object.
14624 * @returns {boolean} Whether the request is for the same origin as the application document.
14625 */
14626function urlIsSameOrigin(requestUrl) {
14627  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14628  return (parsed.protocol === originUrl.protocol &&
14629          parsed.host === originUrl.host);
14630}
14631
14632/**
14633 * @ngdoc service
14634 * @name $window
14635 *
14636 * @description
14637 * A reference to the browser's `window` object. While `window`
14638 * is globally available in JavaScript, it causes testability problems, because
14639 * it is a global variable. In angular we always refer to it through the
14640 * `$window` service, so it may be overridden, removed or mocked for testing.
14641 *
14642 * Expressions, like the one defined for the `ngClick` directive in the example
14643 * below, are evaluated with respect to the current scope.  Therefore, there is
14644 * no risk of inadvertently coding in a dependency on a global value in such an
14645 * expression.
14646 *
14647 * @example
14648   <example module="windowExample">
14649     <file name="index.html">
14650       <script>
14651         angular.module('windowExample', [])
14652           .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
14653             $scope.greeting = 'Hello, World!';
14654             $scope.doGreeting = function(greeting) {
14655               $window.alert(greeting);
14656             };
14657           }]);
14658       </script>
14659       <div ng-controller="ExampleController">
14660         <input type="text" ng-model="greeting" />
14661         <button ng-click="doGreeting(greeting)">ALERT</button>
14662       </div>
14663     </file>
14664     <file name="protractor.js" type="protractor">
14665      it('should display the greeting in the input box', function() {
14666       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14667       // If we click the button it will block the test runner
14668       // element(':button').click();
14669      });
14670     </file>
14671   </example>
14672 */
14673function $WindowProvider(){
14674  this.$get = valueFn(window);
14675}
14676
14677/* global currencyFilter: true,
14678 dateFilter: true,
14679 filterFilter: true,
14680 jsonFilter: true,
14681 limitToFilter: true,
14682 lowercaseFilter: true,
14683 numberFilter: true,
14684 orderByFilter: true,
14685 uppercaseFilter: true,
14686 */
14687
14688/**
14689 * @ngdoc provider
14690 * @name $filterProvider
14691 * @description
14692 *
14693 * Filters are just functions which transform input to an output. However filters need to be
14694 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14695 * annotated with dependencies and is responsible for creating a filter function.
14696 *
14697 * ```js
14698 *   // Filter registration
14699 *   function MyModule($provide, $filterProvider) {
14700 *     // create a service to demonstrate injection (not always needed)
14701 *     $provide.value('greet', function(name){
14702 *       return 'Hello ' + name + '!';
14703 *     });
14704 *
14705 *     // register a filter factory which uses the
14706 *     // greet service to demonstrate DI.
14707 *     $filterProvider.register('greet', function(greet){
14708 *       // return the filter function which uses the greet service
14709 *       // to generate salutation
14710 *       return function(text) {
14711 *         // filters need to be forgiving so check input validity
14712 *         return text && greet(text) || text;
14713 *       };
14714 *     });
14715 *   }
14716 * ```
14717 *
14718 * The filter function is registered with the `$injector` under the filter name suffix with
14719 * `Filter`.
14720 *
14721 * ```js
14722 *   it('should be the same instance', inject(
14723 *     function($filterProvider) {
14724 *       $filterProvider.register('reverse', function(){
14725 *         return ...;
14726 *       });
14727 *     },
14728 *     function($filter, reverseFilter) {
14729 *       expect($filter('reverse')).toBe(reverseFilter);
14730 *     });
14731 * ```
14732 *
14733 *
14734 * For more information about how angular filters work, and how to create your own filters, see
14735 * {@link guide/filter Filters} in the Angular Developer Guide.
14736 */
14737
14738/**
14739 * @ngdoc service
14740 * @name $filter
14741 * @kind function
14742 * @description
14743 * Filters are used for formatting data displayed to the user.
14744 *
14745 * The general syntax in templates is as follows:
14746 *
14747 *         {{ expression [| filter_name[:parameter_value] ... ] }}
14748 *
14749 * @param {String} name Name of the filter function to retrieve
14750 * @return {Function} the filter function
14751 * @example
14752   <example name="$filter" module="filterExample">
14753     <file name="index.html">
14754       <div ng-controller="MainCtrl">
14755        <h3>{{ originalText }}</h3>
14756        <h3>{{ filteredText }}</h3>
14757       </div>
14758     </file>
14759
14760     <file name="script.js">
14761      angular.module('filterExample', [])
14762      .controller('MainCtrl', function($scope, $filter) {
14763        $scope.originalText = 'hello';
14764        $scope.filteredText = $filter('uppercase')($scope.originalText);
14765      });
14766     </file>
14767   </example>
14768  */
14769$FilterProvider.$inject = ['$provide'];
14770function $FilterProvider($provide) {
14771  var suffix = 'Filter';
14772
14773  /**
14774   * @ngdoc method
14775   * @name $filterProvider#register
14776   * @param {string|Object} name Name of the filter function, or an object map of filters where
14777   *    the keys are the filter names and the values are the filter factories.
14778   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14779   *    of the registered filter instances.
14780   */
14781  function register(name, factory) {
14782    if(isObject(name)) {
14783      var filters = {};
14784      forEach(name, function(filter, key) {
14785        filters[key] = register(key, filter);
14786      });
14787      return filters;
14788    } else {
14789      return $provide.factory(name + suffix, factory);
14790    }
14791  }
14792  this.register = register;
14793
14794  this.$get = ['$injector', function($injector) {
14795    return function(name) {
14796      return $injector.get(name + suffix);
14797    };
14798  }];
14799
14800  ////////////////////////////////////////
14801
14802  /* global
14803    currencyFilter: false,
14804    dateFilter: false,
14805    filterFilter: false,
14806    jsonFilter: false,
14807    limitToFilter: false,
14808    lowercaseFilter: false,
14809    numberFilter: false,
14810    orderByFilter: false,
14811    uppercaseFilter: false,
14812  */
14813
14814  register('currency', currencyFilter);
14815  register('date', dateFilter);
14816  register('filter', filterFilter);
14817  register('json', jsonFilter);
14818  register('limitTo', limitToFilter);
14819  register('lowercase', lowercaseFilter);
14820  register('number', numberFilter);
14821  register('orderBy', orderByFilter);
14822  register('uppercase', uppercaseFilter);
14823}
14824
14825/**
14826 * @ngdoc filter
14827 * @name filter
14828 * @kind function
14829 *
14830 * @description
14831 * Selects a subset of items from `array` and returns it as a new array.
14832 *
14833 * @param {Array} array The source array.
14834 * @param {string|Object|function()} expression The predicate to be used for selecting items from
14835 *   `array`.
14836 *
14837 *   Can be one of:
14838 *
14839 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14840 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14841 *     will be returned. The predicate can be negated by prefixing the string with `!`.
14842 *
14843 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14844 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14845 *     which have property `name` containing "M" and property `phone` containing "1". A special
14846 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14847 *     property of the object. That's equivalent to the simple substring match with a `string`
14848 *     as described above. The predicate can be negated by prefixing the string with `!`.
14849 *     For Example `{name: "!M"}` predicate will return an array of items which have property `name`
14850 *     not containing "M".
14851 *
14852 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14853 *     called for each element of `array`. The final result is an array of those elements that
14854 *     the predicate returned true for.
14855 *
14856 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14857 *     determining if the expected value (from the filter expression) and actual value (from
14858 *     the object in the array) should be considered a match.
14859 *
14860 *   Can be one of:
14861 *
14862 *   - `function(actual, expected)`:
14863 *     The function will be given the object value and the predicate value to compare and
14864 *     should return true if the item should be included in filtered result.
14865 *
14866 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14867 *     this is essentially strict comparison of expected and actual.
14868 *
14869 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
14870 *     insensitive way.
14871 *
14872 * @example
14873   <example>
14874     <file name="index.html">
14875       <div ng-init="friends = [{name:'John', phone:'555-1276'},
14876                                {name:'Mary', phone:'800-BIG-MARY'},
14877                                {name:'Mike', phone:'555-4321'},
14878                                {name:'Adam', phone:'555-5678'},
14879                                {name:'Julie', phone:'555-8765'},
14880                                {name:'Juliette', phone:'555-5678'}]"></div>
14881
14882       Search: <input ng-model="searchText">
14883       <table id="searchTextResults">
14884         <tr><th>Name</th><th>Phone</th></tr>
14885         <tr ng-repeat="friend in friends | filter:searchText">
14886           <td>{{friend.name}}</td>
14887           <td>{{friend.phone}}</td>
14888         </tr>
14889       </table>
14890       <hr>
14891       Any: <input ng-model="search.$"> <br>
14892       Name only <input ng-model="search.name"><br>
14893       Phone only <input ng-model="search.phone"><br>
14894       Equality <input type="checkbox" ng-model="strict"><br>
14895       <table id="searchObjResults">
14896         <tr><th>
14896Name</th><th>Phone</th></tr>
14897         <tr ng-repeat="friendObj in friends | filter:search:strict">
14898           <td>{{friendObj.name}}</td>
14899           <td>{{friendObj.phone}}</td>
14900         </tr>
14901       </table>
14902     </file>
14903     <file name="protractor.js" type="protractor">
14904       var expectFriendNames = function(expectedNames, key) {
14905         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14906           arr.forEach(function(wd, i) {
14907             expect(wd.getText()).toMatch(expectedNames[i]);
14908           });
14909         });
14910       };
14911
14912       it('should search across all fields when filtering with a string', function() {
14913         var searchText = element(by.model('searchText'));
14914         searchText.clear();
14915         searchText.sendKeys('m');
14916         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14917
14918         searchText.clear();
14919         searchText.sendKeys('76');
14920         expectFriendNames(['John', 'Julie'], 'friend');
14921       });
14922
14923       it('should search in specific fields when filtering with a predicate object', function() {
14924         var searchAny = element(by.model('search.$'));
14925         searchAny.clear();
14926         searchAny.sendKeys('i');
14927         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14928       });
14929       it('should use a equal comparison when comparator is true', function() {
14930         var searchName = element(by.model('search.name'));
14931         var strict = element(by.model('strict'));
14932         searchName.clear();
14933         searchName.sendKeys('Julie');
14934         strict.click();
14935         expectFriendNames(['Julie'], 'friendObj');
14936       });
14937     </file>
14938   </example>
14939 */
14940function filterFilter() {
14941  return function(array, expression, comparator) {
14942    if (!isArray(array)) return array;
14943
14944    var comparatorType = typeof(comparator),
14945        predicates = [];
14946
14947    predicates.check = function(value) {
14948      for (var j = 0; j < predicates.length; j++) {
14949        if(!predicates[j](value)) {
14950          return false;
14951        }
14952      }
14953      return true;
14954    };
14955
14956    if (comparatorType !== 'function') {
14957      if (comparatorType === 'boolean' && comparator) {
14958        comparator = function(obj, text) {
14959          return angular.equals(obj, text);
14960        };
14961      } else {
14962        comparator = function(obj, text) {
14963          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14964            for (var objKey in obj) {
14965              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14966                  comparator(obj[objKey], text[objKey])) {
14967                return true;
14968              }
14969            }
14970            return false;
14971          }
14972          text = (''+text).toLowerCase();
14973          return (''+obj).toLowerCase().indexOf(text) > -1;
14974        };
14975      }
14976    }
14977
14978    var search = function(obj, text){
14979      if (typeof text === 'string' && text.charAt(0) === '!') {
14980        return !search(obj, text.substr(1));
14981      }
14982      switch (typeof obj) {
14983        case 'boolean':
14984        case 'number':
14985        case 'string':
14986          return comparator(obj, text);
14987        case 'object':
14988          switch (typeof text) {
14989            case 'object':
14990              return comparator(obj, text);
14991            default:
14992              for ( var objKey in obj) {
14993                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14994                  return true;
14995                }
14996              }
14997              break;
14998          }
14999          return false;
15000        case 'array':
15001          for ( var i = 0; i < obj.length; i++) {
15002            if (search(obj[i], text)) {
15003              return true;
15004            }
15005          }
15006          return false;
15007        default:
15008          return false;
15009      }
15010    };
15011    switch (typeof expression) {
15012      case 'boolean':
15013      case 'number':
15014      case 'string':
15015        // Set up expression object and fall through
15016        expression = {$:expression};
15017        // jshint -W086
15018      case 'object':
15019        // jshint +W086
15020        for (var key in expression) {
15021          (function(path) {
15022            if (typeof expression[path] === 'undefined') return;
15023            predicates.push(function(value) {
15024              return search(path == '$' ? value : (value && value[path]), expression[path]);
15025            });
15026          })(key);
15027        }
15028        break;
15029      case 'function':
15030        predicates.push(expression);
15031        break;
15032      default:
15033        return array;
15034    }
15035    var filtered = [];
15036    for ( var j = 0; j < array.length; j++) {
15037      var value = array[j];
15038      if (predicates.check(value)) {
15039        filtered.push(value);
15040      }
15041    }
15042    return filtered;
15043  };
15044}
15045
15046/**
15047 * @ngdoc filter
15048 * @name currency
15049 * @kind function
15050 *
15051 * @description
15052 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
15053 * symbol for current locale is used.
15054 *
15055 * @param {number} amount Input to filter.
15056 * @param {string=} symbol Currency symbol or identifier to be displayed.
15057 * @returns {string} Formatted number.
15058 *
15059 *
15060 * @example
15061   <example module="currencyExample">
15062     <file name="index.html">
15063       <script>
15064         angular.module('currencyExample', [])
15065           .controller('ExampleController', ['$scope', function($scope) {
15066             $scope.amount = 1234.56;
15067           }]);
15068       </script>
15069       <div ng-controller="ExampleController">
15070         <input type="number" ng-model="amount"> <br>
15071         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
15072         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
15073       </div>
15074     </file>
15075     <file name="protractor.js" type="protractor">
15076       it('should init with 1234.56', function() {
15077         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
15078         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
15079       });
15080       it('should update', function() {
15081         if (browser.params.browser == 'safari') {
15082           // Safari does not understand the minus key. See
15083           // https://github.com/angular/protractor/issues/481
15084           return;
15085         }
15086         element(by.model('amount')).clear();
15087         element(by.model('amount')).sendKeys('-1234');
15088         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
15089         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
15090       });
15091     </file>
15092   </example>
15093 */
15094currencyFilter.$inject = ['$locale'];
15095function currencyFilter($locale) {
15096  var formats = $locale.NUMBER_FORMATS;
15097  return function(amount, currencySymbol){
15098    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
15099    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
15100                replace(/\u00A4/g, currencySymbol);
15101  };
15102}
15103
15104/**
15105 * @ngdoc filter
15106 * @name number
15107 * @kind function
15108 *
15109 * @description
15110 * Formats a number as text.
15111 *
15112 * If the input is not a number an empty string is returned.
15113 *
15114 * @param {number|string} number Number to format.
15115 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
15116 * If this is not provided then the fraction size is computed from the current locale's number
15117 * formatting pattern. In the case of the default locale, it will be 3.
15118 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
15119 *
15120 * @example
15121   <example module="numberFilterExample">
15122     <file name="index.html">
15123       <script>
15124         angular.module('numberFilterExample', [])
15125           .controller('ExampleController', ['$scope', function($scope) {
15126             $scope.val = 1234.56789;
15127           }]);
15128       </script>
15129       <div ng-controller="ExampleController">
15130         Enter number: <input ng-model='val'><br>
15131         Default formatting: <span id='number-default'>{{val | number}}</span><br>
15132         No fractions: <span>{{val | number:0}}</span><br>
15133         Negative number: <span>{{-val | number:4}}</span>
15134       </div>
15135     </file>
15136     <file name="protractor.js" type="protractor">
15137       it('should format numbers', function() {
15138         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
15139         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
15140         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
15141       });
15142
15143       it('should update', function() {
15144         element(by.model('val')).clear();
15145         element(by.model('val')).sendKeys('3374.333');
15146         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
15147         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
15148         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
15149      });
15150     </file>
15151   </example>
15152 */
15153
15154
15155numberFilter.$inject = ['$locale'];
15156function numberFilter($locale) {
15157  var formats = $locale.NUMBER_FORMATS;
15158  return function(number, fractionSize) {
15159    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
15160      fractionSize);
15161  };
15162}
15163
15164var DECIMAL_SEP = '.';
15165function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
15166  if (number == null || !isFinite(number) || isObject(number)) return '';
15167
15168  var isNegative = number < 0;
15169  number = Math.abs(number);
15170  var numStr = number + '',
15171      formatedText = '',
15172      parts = [];
15173
15174  var hasExponent = false;
15175  if (numStr.indexOf('e') !== -1) {
15176    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
15177    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
15178      numStr = '0';
15179      number = 0;
15180    } else {
15181      formatedText = numStr;
15182      hasExponent = true;
15183    }
15184  }
15185
15186  if (!hasExponent) {
15187    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
15188
15189    // determine fractionSize if it is not specified
15190    if (isUndefined(fractionSize)) {
15191      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
15192    }
15193
15194    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
15195    // inspired by:
15196    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
15197    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
15198
15199    if (number === 0) {
15200      isNegative = false;
15201    }
15202
15203    var fraction = ('' + number).split(DECIMAL_SEP);
15204    var whole = fraction[0];
15205    fraction = fraction[1] || '';
15206
15207    var i, pos = 0,
15208        lgroup = pattern.lgSize,
15209        group = pattern.gSize;
15210
15211    if (whole.length >= (lgroup + group)) {
15212      pos = whole.length - lgroup;
15213      for (i = 0; i < pos; i++) {
15214        if ((pos - i)%group === 0 && i !== 0) {
15215          formatedText += groupSep;
15216        }
15217        formatedText += whole.charAt(i);
15218      }
15219    }
15220
15221    for (i = pos; i < whole.length; i++) {
15222      if ((whole.length - i)%lgroup === 0 && i !== 0) {
15223        formatedText += groupSep;
15224      }
15225      formatedText += whole.charAt(i);
15226    }
15227
15228    // format fraction part.
15229    while(fraction.length < fractionSize) {
15230      fraction += '0';
15231    }
15232
15233    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
15234  } else {
15235
15236    if (fractionSize > 0 && number > -1 && number < 1) {
15237      formatedText = number.toFixed(fractionSize);
15238    }
15239  }
15240
15241  parts.push(isNegative ? pattern.negPre : pattern.posPre);
15242  parts.push(formatedText);
15243  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
15244  return parts.join('');
15245}
15246
15247function padNumber(num, digits, trim) {
15248  var neg = '';
15249  if (num < 0) {
15250    neg =  '-';
15251    num = -num;
15252  }
15253  num = '' + num;
15254  while(num.length < digits) num = '0' + num;
15255  if (trim)
15256    num = num.substr(num.length - digits);
15257  return neg + num;
15258}
15259
15260
15261function dateGetter(name, size, offset, trim) {
15262  offset = offset || 0;
15263  return function(date) {
15264    var value = date['get' + name]();
15265    if (offset > 0 || value > -offset)
15266      value += offset;
15267    if (value === 0 && offset == -12 ) value = 12;
15268    return padNumber(value, size, trim);
15269  };
15270}
15271
15272function dateStrGetter(name, shortForm) {
15273  return function(date, formats) {
15274    var value = date['get' + name]();
15275    var get = uppercase(shortForm ? ('SHORT' + name) : name);
15276
15277    return formats[get][value];
15278  };
15279}
15280
15281function timeZoneGetter(date) {
15282  var zone = -1 * date.getTimezoneOffset();
15283  var paddedZone = (zone >= 0) ? "+" : "";
15284
15285  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
15286                padNumber(Math.abs(zone % 60), 2);
15287
15288  return paddedZone;
15289}
15290
15291function ampmGetter(date, formats) {
15292  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
15293}
15294
15295var DATE_FORMATS = {
15296  yyyy: dateGetter('FullYear', 4),
15297    yy: dateGetter('FullYear', 2, 0, true),
15298     y: dateGetter('FullYear', 1),
15299  MMMM: dateStrGetter('Month'),
15300   MMM: dateStrGetter('Month', true),
15301    MM: dateGetter('Month', 2, 1),
15302     M: dateGetter('Month', 1, 1),
15303    dd: dateGetter('Date', 2),
15304     d: dateGetter('Date', 1),
15305    HH: dateGetter('Hours', 2),
15306     H: dateGetter('Hours', 1),
15307    hh: dateGetter('Hours', 2, -12),
15308     h: dateGetter('Hours', 1, -12),
15309    mm: dateGetter('Minutes', 2),
15310     m: dateGetter('Minutes', 1),
15311    ss: dateGetter('Seconds', 2),
15312     s: dateGetter('Seconds', 1),
15313     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
15314     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
15315   sss: dateGetter('Milliseconds', 3),
15316  EEEE: dateStrGetter('Day'),
15317   EEE: dateStrGetter('Day', true),
15318     a: ampmGetter,
15319     Z: timeZoneGetter
15320};
15321
15322var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
15323    NUMBER_STRING = /^\-?\d+$/;
15324
15325/**
15326 * @ngdoc filter
15327 * @name date
15328 * @kind function
15329 *
15330 * @description
15331 *   Formats `date` to a string based on the requested `format`.
15332 *
15333 *   `format` string can be composed of the following elements:
15334 *
15335 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
15336 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
15337 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
15338 *   * `'MMMM'`: Month in year (January-December)
15339 *   * `'MMM'`: Month in year (Jan-Dec)
15340 *   * `'MM'`: Month in year, padded (01-12)
15341 *   * `'M'`: Month in year (1-12)
15342 *   * `'dd'`: Day in month, padded (01-31)
15343 *   * `'d'`: Day in month (1-31)
15344 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
15345 *   * `'EEE'`: Day in Week, (Sun-Sat)
15346 *   * `'HH'`: Hour in day, padded (00-23)
15347 *   * `'H'`: Hour in day (0-23)
15348 *   * `'hh'`: Hour in am/pm, padded (01-12)
15349 *   * `'h'`: Hour in am/pm, (1-12)
15350 *   * `'mm'`: Minute in hour, padded (00-59)
15351 *   * `'m'`: Minute in hour (0-59)
15352 *   * `'ss'`: Second in minute, padded (00-59)
15353 *   * `'s'`: Second in minute (0-59)
15354 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
15355 *   * `'a'`: am/pm marker
15356 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
15357 *
15358 *   `format` string can also be one of the following predefined
15359 *   {@link guide/i18n localizable formats}:
15360 *
15361 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
15362 *     (e.g. Sep 3, 2010 12:05:08 pm)
15363 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
15364 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
15365 *     (e.g. Friday, September 3, 2010)
15366 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
15367 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
15368 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
15369 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
15370 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
15371 *
15372 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
15373 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
15374 *   (e.g. `"h 'o''clock'"`).
15375 *
15376 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
15377 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
15378 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
15379 *    specified in the string input, the time is considered to be in the local timezone.
15380 * @param {string=} format Formatting rules (see Description). If not specified,
15381 *    `mediumDate` is used.
15382 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
15383 *
15384 * @example
15385   <example>
15386     <file name="index.html">
15387       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
15388           <span>{{1288323623006 | date:'medium'}}</span><br>
15389       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
15390          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15391       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15392          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15393       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
15394          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
15395     </file>
15396     <file name="protractor.js" type="protractor">
15397       it('should format date', function() {
15398         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
15399            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
15400         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
15401            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15402         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15403            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15404         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
15405            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
15406       });
15407     </file>
15408   </example>
15409 */
15410dateFilter.$inject = ['$locale'];
15411function dateFilter($locale) {
15412
15413
15414  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
15415                     // 1        2       3         4          5          6          7          8  9     10      11
15416  function jsonStringToDate(string) {
15417    var match;
15418    if (match = string.match(R_ISO8601_STR)) {
15419      var date = new Date(0),
15420          tzHour = 0,
15421          tzMin  = 0,
15422          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
15423          timeSetter = match[8] ? date.setUTCHours : date.setHours;
15424
15425      if (match[9]) {
15426        tzHour = int(match[9] + match[10]);
15427        tzMin = int(match[9] + match[11]);
15428      }
15429      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
15430      var h = int(match[4]||0) - tzHour;
15431      var m = int(match[5]||0) - tzMin;
15432      var s = int(match[6]||0);
15433      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
15434      timeSetter.call(date, h, m, s, ms);
15435      return date;
15436    }
15437    return string;
15438  }
15439
15440
15441  return function(date, format) {
15442    var text = '',
15443        parts = [],
15444        fn, match;
15445
15446    format = format || 'mediumDate';
15447    format = $locale.DATETIME_FORMATS[format] || format;
15448    if (isString(date)) {
15449      date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
15450    }
15451
15452    if (isNumber(date)) {
15453      date = new Date(date);
15454    }
15455
15456    if (!isDate(date)) {
15457      return date;
15458    }
15459
15460    while(format) {
15461      match = DATE_FORMATS_SPLIT.exec(format);
15462      if (match) {
15463        parts = concat(parts, match, 1);
15464        format = parts.pop();
15465      } else {
15466        parts.push(format);
15467        format = null;
15468      }
15469    }
15470
15471    forEach(parts, function(value){
15472      fn = DATE_FORMATS[value];
15473      text += fn ? fn(date, $locale.DATETIME_FORMATS)
15474                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
15475    });
15476
15477    return text;
15478  };
15479}
15480
15481
15482/**
15483 * @ngdoc filter
15484 * @name json
15485 * @kind function
15486 *
15487 * @description
15488 *   Allows you to convert a JavaScript object into JSON string.
15489 *
15490 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
15491 *   the binding is automatically converted to JSON.
15492 *
15493 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
15494 * @returns {string} JSON string.
15495 *
15496 *
15497 * @example
15498   <example>
15499     <file name="index.html">
15500       <pre>{{ {'name':'value'} | json }}</pre>
15501     </file>
15502     <file name="protractor.js" type="protractor">
15503       it('should jsonify filtered objects', function() {
15504         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15505       });
15506     </file>
15507   </example>
15508 *
15509 */
15510function jsonFilter() {
15511  return function(object) {
15512    return toJson(object, true);
15513  };
15514}
15515
15516
15517/**
15518 * @ngdoc filter
15519 * @name lowercase
15520 * @kind function
15521 * @description
15522 * Converts string to lowercase.
15523 * @see angular.lowercase
15524 */
15525var lowercaseFilter = valueFn(lowercase);
15526
15527
15528/**
15529 * @ngdoc filter
15530 * @name uppercase
15531 * @kind function
15532 * @description
15533 * Converts string to uppercase.
15534 * @see angular.uppercase
15535 */
15536var uppercaseFilter = valueFn(uppercase);
15537
15538/**
15539 * @ngdoc filter
15540 * @name limitTo
15541 * @kind function
15542 *
15543 * @description
15544 * Creates a new array or string containing only a specified number of elements. The elements
15545 * are taken from either the beginning or the end of the source array or string, as specified by
15546 * the value and sign (positive or negative) of `limit`.
15547 *
15548 * @param {Array|string} input Source array or string to be limited.
15549 * @param {string|number} limit The length of the returned array or string. If the `limit` number
15550 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15551 *     If the number is negative, `limit` number  of items from the end of the source array/string
15552 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15553 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15554 *     had less than `limit` elements.
15555 *
15556 * @example
15557   <example module="limitToExample">
15558     <file name="index.html">
15559       <script>
15560         angular.module('limitToExample', [])
15561           .controller('ExampleController', ['$scope', function($scope) {
15562             $scope.numbers = [1,2,3,4,5,6,7,8,9];
15563             $scope.letters = "abcdefghi";
15564             $scope.numLimit = 3;
15565             $scope.letterLimit = 3;
15566           }]);
15567       </script>
15568       <div ng-controller="ExampleController">
15569         Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
15570         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15571         Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
15572         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15573       </div>
15574     </file>
15575     <file name="protractor.js" type="protractor">
15576       var numLimitInput = element(by.model('numLimit'));
15577       var letterLimitInput = element(by.model('letterLimit'));
15578       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15579       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15580
15581       it('should limit the number array to first three items', function() {
15582         expect(numLimitInput.getAttribute('value')).toBe('3');
15583         expect(letterLimitInput.getAttribute('value')).toBe('3');
15584         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15585         expect(limitedLetters.getText()).toEqual('Output letters: abc');
15586       });
15587
15588       // There is a bug in safari and protractor that doesn't like the minus key
15589       // it('should update the output when -3 is entered', function() {
15590       //   numLimitInput.clear();
15591       //   numLimitInput.sendKeys('-3');
15592       //   letterLimitInput.clear();
15593       //   letterLimitInput.sendKeys('-3');
15594       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15595       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15596       // });
15597
15598       it('should not exceed the maximum size of input array', function() {
15599         numLimitInput.clear();
15600         numLimitInput.sendKeys('100');
15601         letterLimitInput.clear();
15602         letterLimitInput.sendKeys('100');
15603         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15604         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15605       });
15606     </file>
15607   </example>
15608 */
15609function limitToFilter(){
15610  return function(input, limit) {
15611    if (!isArray(input) && !isString(input)) return input;
15612
15613    if (Math.abs(Number(limit)) === Infinity) {
15614      limit = Number(limit);
15615    } else {
15616      limit = int(limit);
15617    }
15618
15619    //NaN check on limit
15620    if (limit) {
15621      return limit > 0 ? input.slice(0, limit) : input.slice(limit);
15622    } else {
15623      return isString(input) ? "" : [];
15624    }
15625  };
15626}
15627
15628/**
15629 * @ngdoc filter
15630 * @name orderBy
15631 * @kind function
15632 *
15633 * @description
15634 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
15635 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
15636 * correctly, make sure they are actually being saved as numbers and not strings.
15637 *
15638 * @param {Array} array The array to sort.
15639 * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
15640 *    used by the comparator to determine the order of elements.
15641 *
15642 *    Can be one of:
15643 *
15644 *    - `function`: Getter function. The result of this function will be sorted using the
15645 *      `<`, `=`, `>` operator.
15646 *    - `string`: An Angular expression. The result of this expression is used to compare elements
15647 *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
15648 *      3 first characters of a property called `name`). The result of a constant expression
15649 *      is interpreted as a property name to be used in comparisons (for example `"special name"`
15650 *      to sort object by the value of their `special name` property). An expression can be
15651 *      optionally prefixed with `+` or `-` to control ascending or descending sort order
15652 *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
15653 *      element itself is used to compare where sorting.
15654 *    - `Array`: An array of function or string predicates. The first predicate in the array
15655 *      is used for sorting, but when two items are equivalent, the next predicate is used.
15656 *
15657 *    If the predicate is missing or empty then it defaults to `'+'`.
15658 *
15659 * @param {boolean=} reverse Reverse the order of the array.
15660 * @returns {Array} Sorted copy of the source array.
15661 *
15662 * @example
15663   <example module="orderByExample">
15664     <file name="index.html">
15665       <script>
15666         angular.module('orderByExample', [])
15667           .controller('ExampleController', ['$scope', function($scope) {
15668             $scope.friends =
15669                 [{name:'John', phone:'555-1212', age:10},
15670                  {name:'Mary', phone:'555-9876', age:19},
15671                  {name:'Mike', phone:'555-4321', age:21},
15672                  {name:'Adam', phone:'555-5678', age:35},
15673                  {name:'Julie', phone:'555-8765', age:29}];
15674             $scope.predicate = '-age';
15675           }]);
15676       </script>
15677       <div ng-controller="ExampleController">
15678         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15679         <hr/>
15680         [ <a href="" ng-click="predicate=''">unsorted</a> ]
15681         <table class="friend">
15682           <tr>
15683             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15684                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15685             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15686             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15687           </tr>
15688           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15689             <td>{{friend.name}}</td>
15690             <td>{{friend.phone}}</td>
15691             <td>{{friend.age}}</td>
15692           </tr>
15693         </table>
15694       </div>
15695     </file>
15696   </example>
15697 *
15698 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
15699 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
15700 * desired parameters.
15701 *
15702 * Example:
15703 *
15704 * @example
15705  <example module="orderByExample">
15706    <file name="index.html">
15707      <div ng-controller="ExampleController">
15708        <table class="friend">
15709          <tr>
15710            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
15711              (<a href="" ng-click="order('-name',false)">^</a>)</th>
15712            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
15713            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
15714          </tr>
15715          <tr ng-repeat="friend in friends">
15716            <td>{{friend.name}}</td>
15717            <td>{{friend.phone}}</td>
15718            <td>{{friend.age}}</td>
15719          </tr>
15720        </table>
15721      </div>
15722    </file>
15723
15724    <file name="script.js">
15725      angular.module('orderByExample', [])
15726        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
15727          var orderBy = $filter('orderBy');
15728          $scope.friends = [
15729            { name: 'John',    phone: '555-1212',    age: 10 },
15730            { name: 'Mary',    phone: '555-9876',    age: 19 },
15731            { name: 'Mike',    phone: '555-4321',    age: 21 },
15732            { name: 'Adam',    phone: '555-5678',    age: 35 },
15733            { name: 'Julie',   phone: '555-8765',    age: 29 }
15734          ];
15735          $scope.order = function(predicate, reverse) {
15736            $scope.friends = orderBy($scope.friends, predicate, reverse);
15737          };
15738          $scope.order('-age',false);
15739        }]);
15740    </file>
15741</example>
15742 */
15743orderByFilter.$inject = ['$parse'];
15744function orderByFilter($parse){
15745  return function(array, sortPredicate, reverseOrder) {
15746    if (!(isArrayLike(array))) return array;
15747    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15748    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
15749    sortPredicate = map(sortPredicate, function(predicate){
15750      var descending = false, get = predicate || identity;
15751      if (isString(predicate)) {
15752        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15753          descending = predicate.charAt(0) == '-';
15754          predicate = predicate.substring(1);
15755        }
15756        if ( predicate === '' ) {
15757          // Effectively no predicate was passed so we compare identity
15758          return reverseComparator(function(a,b) {
15759            return compare(a, b);
15760          }, descending);
15761        }
15762        get = $parse(predicate);
15763        if (get.constant) {
15764          var key = get();
15765          return reverseComparator(function(a,b) {
15766            return compare(a[key], b[key]);
15767          }, descending);
15768        }
15769      }
15770      return reverseComparator(function(a,b){
15771        return compare(get(a),get(b));
15772      }, descending);
15773    });
15774    return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
15775
15776    function comparator(o1, o2){
15777      for ( var i = 0; i < sortPredicate.length; i++) {
15778        var comp = sortPredicate[i](o1, o2);
15779        if (comp !== 0) return comp;
15780      }
15781      return 0;
15782    }
15783    function reverseComparator(comp, descending) {
15784      return toBoolean(descending)
15785          ? function(a,b){return comp(b,a);}
15786          : comp;
15787    }
15788    function compare(v1, v2){
15789      var t1 = typeof v1;
15790      var t2 = typeof v2;
15791      if (t1 == t2) {
15792        if (isDate(v1) && isDate(v2)) {
15793          v1 = v1.valueOf();
15794          v2 = v2.valueOf();
15795        }
15796        if (t1 == "string") {
15797           v1 = v1.toLowerCase();
15798           v2 = v2.toLowerCase();
15799        }
15800        if (v1 === v2) return 0;
15801        return v1 < v2 ? -1 : 1;
15802      } else {
15803        return t1 < t2 ? -1 : 1;
15804      }
15805    }
15806  };
15807}
15808
15809function ngDirective(directive) {
15810  if (isFunction(directive)) {
15811    directive = {
15812      link: directive
15813    };
15814  }
15815  directive.restrict = directive.restrict || 'AC';
15816  return valueFn(directive);
15817}
15818
15819/**
15820 * @ngdoc directive
15821 * @name a
15822 * @restrict E
15823 *
15824 * @description
15825 * Modifies the default behavior of the html A tag so that the default action is prevented when
15826 * the href attribute is empty.
15827 *
15828 * This change permits the easy creation of action links with the `ngClick` directive
15829 * without changing the location or causing page reloads, e.g.:
15830 * `<a href="" ng-click="list.addItem()">Add Item</a>`
15831 */
15832var htmlAnchorDirective = valueFn({
15833  restrict: 'E',
15834  compile: function(element, attr) {
15835
15836    if (msie <= 8) {
15837
15838      // turn <a href ng-click="..">link</a> into a stylable link in IE
15839      // but only if it doesn't have name attribute, in which case it's an anchor
15840      if (!attr.href && !attr.name) {
15841        attr.$set('href', '');
15842      }
15843
15844      // add a comment node to anchors to workaround IE bug that causes element content to be reset
15845      // to new attribute content if attribute is updated with value containing @ and element also
15846      // contains value with @
15847      // see issue #1949
15848      element.append(document.createComment('IE fix'));
15849    }
15850
15851    if (!attr.href && !attr.xlinkHref && !attr.name) {
15852      return function(scope, element) {
15853        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15854        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15855                   'xlink:href' : 'href';
15856        element.on('click', function(event){
15857          // if we have no href url, then don't navigate anywhere.
15858          if (!element.attr(href)) {
15859            event.preventDefault();
15860          }
15861        });
15862      };
15863    }
15864  }
15865});
15866
15867/**
15868 * @ngdoc directive
15869 * @name ngHref
15870 * @restrict A
15871 * @priority 99
15872 *
15873 * @description
15874 * Using Angular markup like `{{hash}}` in an href attribute will
15875 * make the link go to the wrong URL if the user clicks it before
15876 * Angular has a chance to replace the `{{hash}}
15876` markup with its
15877 * value. Until Angular replaces the markup the link will be broken
15878 * and will most likely return a 404 error. The `ngHref` directive
15879 * solves this problem.
15880 *
15881 * The wrong way to write it:
15882 * ```html
15883 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15884 * ```
15885 *
15886 * The correct way to write it:
15887 * ```html
15888 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15889 * ```
15890 *
15891 * @element A
15892 * @param {template} ngHref any string which can contain `{{}}` markup.
15893 *
15894 * @example
15895 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15896 * in links and their different behaviors:
15897    <example>
15898      <file name="index.html">
15899        <input ng-model="value" /><br />
15900        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15901        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15902        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15903        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15904        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15905        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15906      </file>
15907      <file name="protractor.js" type="protractor">
15908        it('should execute ng-click but not reload when href without value', function() {
15909          element(by.id('link-1')).click();
15910          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15911          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15912        });
15913
15914        it('should execute ng-click but not reload when href empty string', function() {
15915          element(by.id('link-2')).click();
15916          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15917          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15918        });
15919
15920        it('should execute ng-click and change url when ng-href specified', function() {
15921          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15922
15923          element(by.id('link-3')).click();
15924
15925          // At this point, we navigate away from an Angular page, so we need
15926          // to use browser.driver to get the base webdriver.
15927
15928          browser.wait(function() {
15929            return browser.driver.getCurrentUrl().then(function(url) {
15930              return url.match(/\/123$/);
15931            });
15932          }, 5000, 'page should navigate to /123');
15933        });
15934
15935        xit('should execute ng-click but not reload when href empty string and name specified', function() {
15936          element(by.id('link-4')).click();
15937          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15938          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15939        });
15940
15941        it('should execute ng-click but not reload when no href but name specified', function() {
15942          element(by.id('link-5')).click();
15943          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15944          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15945        });
15946
15947        it('should only change url when only ng-href', function() {
15948          element(by.model('value')).clear();
15949          element(by.model('value')).sendKeys('6');
15950          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15951
15952          element(by.id('link-6')).click();
15953
15954          // At this point, we navigate away from an Angular page, so we need
15955          // to use browser.driver to get the base webdriver.
15956          browser.wait(function() {
15957            return browser.driver.getCurrentUrl().then(function(url) {
15958              return url.match(/\/6$/);
15959            });
15960          }, 5000, 'page should navigate to /6');
15961        });
15962      </file>
15963    </example>
15964 */
15965
15966/**
15967 * @ngdoc directive
15968 * @name ngSrc
15969 * @restrict A
15970 * @priority 99
15971 *
15972 * @description
15973 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15974 * work right: The browser will fetch from the URL with the literal
15975 * text `{{hash}}` until Angular replaces the expression inside
15976 * `{{hash}}`. The `ngSrc` directive solves this problem.
15977 *
15978 * The buggy way to write it:
15979 * ```html
15980 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15981 * ```
15982 *
15983 * The correct way to write it:
15984 * ```html
15985 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15986 * ```
15987 *
15988 * @element IMG
15989 * @param {template} ngSrc any string which can contain `{{}}` markup.
15990 */
15991
15992/**
15993 * @ngdoc directive
15994 * @name ngSrcset
15995 * @restrict A
15996 * @priority 99
15997 *
15998 * @description
15999 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
16000 * work right: The browser will fetch from the URL with the literal
16001 * text `{{hash}}` until Angular replaces the expression inside
16002 * `{{hash}}`. The `ngSrcset` directive solves this problem.
16003 *
16004 * The buggy way to write it:
16005 * ```html
16006 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
16007 * ```
16008 *
16009 * The correct way to write it:
16010 * ```html
16011 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
16012 * ```
16013 *
16014 * @element IMG
16015 * @param {template} ngSrcset any string which can contain `{{}}` markup.
16016 */
16017
16018/**
16019 * @ngdoc directive
16020 * @name ngDisabled
16021 * @restrict A
16022 * @priority 100
16023 *
16024 * @description
16025 *
16026 * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
16027 * ```html
16028 * <div ng-init="scope = { isDisabled: false }">
16029 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
16030 * </div>
16031 * ```
16032 *
16033 * The HTML specification does not require browsers to preserve the values of boolean attributes
16034 * such as disabled. (Their presence means true and their absence means false.)
16035 * If we put an Angular interpolation expression into such an attribute then the
16036 * binding information would be lost when the browser removes the attribute.
16037 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
16038 * This complementary directive is not removed by the browser and so provides
16039 * a permanent reliable place to store the binding information.
16040 *
16041 * @example
16042    <example>
16043      <file name="index.html">
16044        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
16045        <button ng-model="button" ng-disabled="checked">Button</button>
16046      </file>
16047      <file name="protractor.js" type="protractor">
16048        it('should toggle button', function() {
16049          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
16050          element(by.model('checked')).click();
16051          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
16052        });
16053      </file>
16054    </example>
16055 *
16056 * @element INPUT
16057 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
16058 *     then special attribute "disabled" will be set on the element
16059 */
16060
16061
16062/**
16063 * @ngdoc directive
16064 * @name ngChecked
16065 * @restrict A
16066 * @priority 100
16067 *
16068 * @description
16069 * The HTML specification does not require browsers to preserve the values of boolean attributes
16070 * such as checked. (Their presence means true and their absence means false.)
16071 * If we put an Angular interpolation expression into such an attribute then the
16072 * binding information would be lost when the browser removes the attribute.
16073 * The `ngChecked` directive solves this problem for the `checked` attribute.
16074 * This complementary directive is not removed by the browser and so provides
16075 * a permanent reliable place to store the binding information.
16076 * @example
16077    <example>
16078      <file name="index.html">
16079        Check me to check both: <input type="checkbox" ng-model="master"><br/>
16080        <input id="checkSlave" type="checkbox" ng-checked="master">
16081      </file>
16082      <file name="protractor.js" type="protractor">
16083        it('should check both checkBoxes', function() {
16084          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
16085          element(by.model('master')).click();
16086          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
16087        });
16088      </file>
16089    </example>
16090 *
16091 * @element INPUT
16092 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
16093 *     then special attribute "checked" will be set on the element
16094 */
16095
16096
16097/**
16098 * @ngdoc directive
16099 * @name ngReadonly
16100 * @restrict A
16101 * @priority 100
16102 *
16103 * @description
16104 * The HTML specification does not require browsers to preserve the values of boolean attributes
16105 * such as readonly. (Their presence means true and their absence means false.)
16106 * If we put an Angular interpolation expression into such an attribute then the
16107 * binding information would be lost when the browser removes the attribute.
16108 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
16109 * This complementary directive is not removed by the browser and so provides
16110 * a permanent reliable place to store the binding information.
16111 * @example
16112    <example>
16113      <file name="index.html">
16114        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
16115        <input type="text" ng-readonly="checked" value="I'm Angular"/>
16116      </file>
16117      <file name="protractor.js" type="protractor">
16118        it('should toggle readonly attr', function() {
16119          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
16120          element(by.model('checked')).click();
16121          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
16122        });
16123      </file>
16124    </example>
16125 *
16126 * @element INPUT
16127 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
16128 *     then special attribute "readonly" will be set on the element
16129 */
16130
16131
16132/**
16133 * @ngdoc directive
16134 * @name ngSelected
16135 * @restrict A
16136 * @priority 100
16137 *
16138 * @description
16139 * The HTML specification does not require browsers to preserve the values of boolean attributes
16140 * such as selected. (Their presence means true and their absence means false.)
16141 * If we put an Angular interpolation expression into such an attribute then the
16142 * binding information would be lost when the browser removes the attribute.
16143 * The `ngSelected` directive solves this problem for the `selected` attribute.
16144 * This complementary directive is not removed by the browser and so provides
16145 * a permanent reliable place to store the binding information.
16146 *
16147 * @example
16148    <example>
16149      <file name="index.html">
16150        Check me to select: <input type="checkbox" ng-model="selected"><br/>
16151        <select>
16152          <option>Hello!</option>
16153          <option id="greet" ng-selected="selected">Greetings!</option>
16154        </select>
16155      </file>
16156      <file name="protractor.js" type="protractor">
16157        it('should select Greetings!', function() {
16158          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
16159          element(by.model('selected')).click();
16160          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
16161        });
16162      </file>
16163    </example>
16164 *
16165 * @element OPTION
16166 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
16167 *     then special attribute "selected" will be set on the element
16168 */
16169
16170/**
16171 * @ngdoc directive
16172 * @name ngOpen
16173 * @restrict A
16174 * @priority 100
16175 *
16176 * @description
16177 * The HTML specification does not require browsers to preserve the values of boolean attributes
16178 * such as open. (Their presence means true and their absence means false.)
16179 * If we put an Angular interpolation expression into such an attribute then the
16180 * binding information would be lost when the browser removes the attribute.
16181 * The `ngOpen` directive solves this problem for the `open` attribute.
16182 * This complementary directive is not removed by the browser and so provides
16183 * a permanent reliable place to store the binding information.
16184 * @example
16185     <example>
16186       <file name="index.html">
16187         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
16188         <details id="details" ng-open="open">
16189            <summary>Show/Hide me</summary>
16190         </details>
16191       </file>
16192       <file name="protractor.js" type="protractor">
16193         it('should toggle open', function() {
16194           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
16195           element(by.model('open')).click();
16196           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
16197         });
16198       </file>
16199     </example>
16200 *
16201 * @element DETAILS
16202 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
16203 *     then special attribute "open" will be set on the element
16204 */
16205
16206var ngAttributeAliasDirectives = {};
16207
16208
16209// boolean attrs are evaluated
16210forEach(BOOLEAN_ATTR, function(propName, attrName) {
16211  // binding to multiple is not supported
16212  if (propName == "multiple") return;
16213
16214  var normalized = directiveNormalize('ng-' + attrName);
16215  ngAttributeAliasDirectives[normalized] = function() {
16216    return {
16217      priority: 100,
16218      link: function(scope, element, attr) {
16219        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
16220          attr.$set(attrName, !!value);
16221        });
16222      }
16223    };
16224  };
16225});
16226
16227
16228// ng-src, ng-srcset, ng-href are interpolated
16229forEach(['src', 'srcset', 'href'], function(attrName) {
16230  var normalized = directiveNormalize('ng-' + attrName);
16231  ngAttributeAliasDirectives[normalized] = function() {
16232    return {
16233      priority: 99, // it needs to run after the attributes are interpolated
16234      link: function(scope, element, attr) {
16235        var propName = attrName,
16236            name = attrName;
16237
16238        if (attrName === 'href' &&
16239            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
16240          name = 'xlinkHref';
16241          attr.$attr[name] = 'xlink:href';
16242          propName = null;
16243        }
16244
16245        attr.$observe(normalized, function(value) {
16246          if (!value) {
16247            if (attrName === 'href') {
16248              attr.$set(name, null);
16249            }
16250            return;
16251          }
16252
16253          attr.$set(name, value);
16254
16255          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
16256          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
16257          // to set the property as well to achieve the desired effect.
16258          // we use attr[attrName] value since $set can sanitize the url.
16259          if (msie && propName) element.prop(propName, attr[name]);
16260        });
16261      }
16262    };
16263  };
16264});
16265
16266/* global -nullFormCtrl */
16267var nullFormCtrl = {
16268  $addControl: noop,
16269  $removeControl: noop,
16270  $setValidity: noop,
16271  $setDirty: noop,
16272  $setPristine: noop
16273};
16274
16275/**
16276 * @ngdoc type
16277 * @name form.FormController
16278 *
16279 * @property {boolean} $pristine True if user has not interacted with the form yet.
16280 * @property {boolean} $dirty True if user has already interacted with the form.
16281 * @property {boolean} $valid True if all of the containing forms and controls are valid.
16282 * @property {boolean}
16282 $invalid True if at least one containing control or form is invalid.
16283 *
16284 * @property {Object} $error Is an object hash, containing references to all invalid controls or
16285 *  forms, where:
16286 *
16287 *  - keys are validation tokens (error names),
16288 *  - values are arrays of controls or forms that are invalid for given error name.
16289 *
16290 *
16291 *  Built-in validation tokens:
16292 *
16293 *  - `email`
16294 *  - `max`
16295 *  - `maxlength`
16296 *  - `min`
16297 *  - `minlength`
16298 *  - `number`
16299 *  - `pattern`
16300 *  - `required`
16301 *  - `url`
16302 *
16303 * @description
16304 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
16305 * such as being valid/invalid or dirty/pristine.
16306 *
16307 * Each {@link ng.directive:form form} directive creates an instance
16308 * of `FormController`.
16309 *
16310 */
16311//asks for $scope to fool the BC controller module
16312FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
16313function FormController(element, attrs, $scope, $animate) {
16314  var form = this,
16315      parentForm = element.parent().controller('form') || nullFormCtrl,
16316      invalidCount = 0, // used to easily determine if we are valid
16317      errors = form.$error = {},
16318      controls = [];
16319
16320  // init state
16321  form.$name = attrs.name || attrs.ngForm;
16322  form.$dirty = false;
16323  form.$pristine = true;
16324  form.$valid = true;
16325  form.$invalid = false;
16326
16327  parentForm.$addControl(form);
16328
16329  // Setup initial state of the control
16330  element.addClass(PRISTINE_CLASS);
16331  toggleValidCss(true);
16332
16333  // convenience method for easy toggling of classes
16334  function toggleValidCss(isValid, validationErrorKey) {
16335    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16336    $animate.setClass(element,
16337      (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
16338      (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16339  }
16340
16341  /**
16342   * @ngdoc method
16343   * @name form.FormController#$addControl
16344   *
16345   * @description
16346   * Register a control with the form.
16347   *
16348   * Input elements using ngModelController do this automatically when they are linked.
16349   */
16350  form.$addControl = function(control) {
16351    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
16352    // and not added to the scope.  Now we throw an error.
16353    assertNotHasOwnProperty(control.$name, 'input');
16354    controls.push(control);
16355
16356    if (control.$name) {
16357      form[control.$name] = control;
16358    }
16359  };
16360
16361  /**
16362   * @ngdoc method
16363   * @name form.FormController#$removeControl
16364   *
16365   * @description
16366   * Deregister a control from the form.
16367   *
16368   * Input elements using ngModelController do this automatically when they are destroyed.
16369   */
16370  form.$removeControl = function(control) {
16371    if (control.$name && form[control.$name] === control) {
16372      delete form[control.$name];
16373    }
16374    forEach(errors, function(queue, validationToken) {
16375      form.$setValidity(validationToken, true, control);
16376    });
16377
16378    arrayRemove(controls, control);
16379  };
16380
16381  /**
16382   * @ngdoc method
16383   * @name form.FormController#$setValidity
16384   *
16385   * @description
16386   * Sets the validity of a form control.
16387   *
16388   * This method will also propagate to parent forms.
16389   */
16390  form.$setValidity = function(validationToken, isValid, control) {
16391    var queue = errors[validationToken];
16392
16393    if (isValid) {
16394      if (queue) {
16395        arrayRemove(queue, control);
16396        if (!queue.length) {
16397          invalidCount--;
16398          if (!invalidCount) {
16399            toggleValidCss(isValid);
16400            form.$valid = true;
16401            form.$invalid = false;
16402          }
16403          errors[validationToken] = false;
16404          toggleValidCss(true, validationToken);
16405          parentForm.$setValidity(validationToken, true, form);
16406        }
16407      }
16408
16409    } else {
16410      if (!invalidCount) {
16411        toggleValidCss(isValid);
16412      }
16413      if (queue) {
16414        if (includes(queue, control)) return;
16415      } else {
16416        errors[validationToken] = queue = [];
16417        invalidCount++;
16418        toggleValidCss(false, validationToken);
16419        parentForm.$setValidity(validationToken, false, form);
16420      }
16421      queue.push(control);
16422
16423      form.$valid = false;
16424      form.$invalid = true;
16425    }
16426  };
16427
16428  /**
16429   * @ngdoc method
16430   * @name form.FormController#$setDirty
16431   *
16432   * @description
16433   * Sets the form to a dirty state.
16434   *
16435   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
16436   * state (ng-dirty class). This method will also propagate to parent forms.
16437   */
16438  form.$setDirty = function() {
16439    $animate.removeClass(element, PRISTINE_CLASS);
16440    $animate.addClass(element, DIRTY_CLASS);
16441    form.$dirty = true;
16442    form.$pristine = false;
16443    parentForm.$setDirty();
16444  };
16445
16446  /**
16447   * @ngdoc method
16448   * @name form.FormController#$setPristine
16449   *
16450   * @description
16451   * Sets the form to its pristine state.
16452   *
16453   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
16454   * state (ng-pristine class). This method will also propagate to all the controls contained
16455   * in this form.
16456   *
16457   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
16458   * saving or resetting it.
16459   */
16460  form.$setPristine = function () {
16461    $animate.removeClass(element, DIRTY_CLASS);
16462    $animate.addClass(element, PRISTINE_CLASS);
16463    form.$dirty = false;
16464    form.$pristine = true;
16465    forEach(controls, function(control) {
16466      control.$setPristine();
16467    });
16468  };
16469}
16470
16471
16472/**
16473 * @ngdoc directive
16474 * @name ngForm
16475 * @restrict EAC
16476 *
16477 * @description
16478 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
16479 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
16480 * sub-group of controls needs to be determined.
16481 *
16482 * Note: the purpose of `ngForm` is to group controls,
16483 * but not to be a replacement for the `<form>` tag with all of its capabilities
16484 * (e.g. posting to the server, ...).
16485 *
16486 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
16487 *                       related scope, under this name.
16488 *
16489 */
16490
16491 /**
16492 * @ngdoc directive
16493 * @name form
16494 * @restrict E
16495 *
16496 * @description
16497 * Directive that instantiates
16498 * {@link form.FormController FormController}.
16499 *
16500 * If the `name` attribute is specified, the form controller is published onto the current scope under
16501 * this name.
16502 *
16503 * # Alias: {@link ng.directive:ngForm `ngForm`}
16504 *
16505 * In Angular forms can be nested. This means that the outer form is valid when all of the child
16506 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
16507 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
16508 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
16509 * using Angular validation directives in forms that are dynamically generated using the
16510 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
16511 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
16512 * `ngForm` directive and nest these in an outer `form` element.
16513 *
16514 *
16515 * # CSS classes
16516 *  - `ng-valid` is set if the form is valid.
16517 *  - `ng-invalid` is set if the form is invalid.
16518 *  - `ng-pristine` is set if the form is pristine.
16519 *  - `ng-dirty` is set if the form is dirty.
16520 *
16521 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
16522 *
16523 *
16524 * # Submitting a form and preventing the default action
16525 *
16526 * Since the role of forms in client-side Angular applications is different than in classical
16527 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
16528 * page reload that sends the data to the server. Instead some javascript logic should be triggered
16529 * to handle the form submission in an application-specific way.
16530 *
16531 * For this reason, Angular prevents the default action (form submission to the server) unless the
16532 * `<form>` element has an `action` attribute specified.
16533 *
16534 * You can use one of the following two ways to specify what javascript method should be called when
16535 * a form is submitted:
16536 *
16537 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
16538 * - {@link ng.directive:ngClick ngClick} directive on the first
16539  *  button or input field of type submit (input[type=submit])
16540 *
16541 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
16542 * or {@link ng.directive:ngClick ngClick} directives.
16543 * This is because of the following form submission rules in the HTML specification:
16544 *
16545 * - If a form has only one input field then hitting enter in this field triggers form submit
16546 * (`ngSubmit`)
16547 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
16548 * doesn't trigger submit
16549 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16550 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16551 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16552 *
16553 *
16554 * ## Animation Hooks
16555 *
16556 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16557 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16558 * other validations that are performed within the form. Animations in ngForm are similar to how
16559 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16560 * as JS animations.
16561 *
16562 * The following example shows a simple way to utilize CSS transitions to style a form element
16563 * that has been rendered as invalid after it has been validated:
16564 *
16565 * <pre>
16566 * //be sure to include ngAnimate as a module to hook into more
16567 * //advanced animations
16568 * .my-form {
16569 *   transition:0.5s linear all;
16570 *   background: white;
16571 * }
16572 * .my-form.ng-invalid {
16573 *   background: red;
16574 *   color:white;
16575 * }
16576 * </pre>
16577 *
16578 * @example
16579    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
16580      <file name="index.html">
16581       <script>
16582         angular.module('formExample', [])
16583           .controller('FormController', ['$scope', function($scope) {
16584             $scope.userType = 'guest';
16585           }]);
16586       </script>
16587       <style>
16588        .my-form {
16589          -webkit-transition:all linear 0.5s;
16590          transition:all linear 0.5s;
16591          background: transparent;
16592        }
16593        .my-form.ng-invalid {
16594          background: red;
16595        }
16596       </style>
16597       <form name="myForm" ng-controller="FormController" class="my-form">
16598         userType: <input name="input" ng-model="userType" required>
16599         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16600         <tt>userType = {{userType}}</tt><br>
16601         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16602         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16603         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16604         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16605        </form>
16606      </file>
16607      <file name="protractor.js" type="protractor">
16608        it('should initialize to model', function() {
16609          var userType = element(by.binding('userType'));
16610          var valid = element(by.binding('myForm.input.$valid'));
16611
16612          expect(userType.getText()).toContain('guest');
16613          expect(valid.getText()).toContain('true');
16614        });
16615
16616        it('should be invalid if empty', function() {
16617          var userType = element(by.binding('userType'));
16618          var valid = element(by.binding('myForm.input.$valid'));
16619          var userInput = element(by.model('userType'));
16620
16621          userInput.clear();
16622          userInput.sendKeys('');
16623
16624          expect(userType.getText()).toEqual('userType =');
16625          expect(valid.getText()).toContain('false');
16626        });
16627      </file>
16628    </example>
16629 *
16630 * @param {string=} name Name of the form. If specified, the form controller will be published into
16631 *                       related scope, under this name.
16632 */
16633var formDirectiveFactory = function(isNgForm) {
16634  return ['$timeout', function($timeout) {
16635    var formDirective = {
16636      name: 'form',
16637      restrict: isNgForm ? 'EAC' : 'E',
16638      controller: FormController,
16639      compile: function() {
16640        return {
16641          pre: function(scope, formElement, attr, controller) {
16642            if (!attr.action) {
16643              // we can't use jq events because if a form is destroyed during submission the default
16644              // action is not prevented. see #1238
16645              //
16646              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16647              // page reload if the form was destroyed by submission of the form via a click handler
16648              // on a button in the form. Looks like an IE9 specific bug.
16649              var preventDefaultListener = function(event) {
16650                event.preventDefault
16651                  ? event.preventDefault()
16652                  : event.returnValue = false; // IE
16653              };
16654
16655              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16656
16657              // unregister the preventDefault listener so that we don't not leak memory but in a
16658              // way that will achieve the prevention of the default action.
16659              formElement.on('$destroy', function() {
16660                $timeout(function() {
16661                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16662                }, 0, false);
16663              });
16664            }
16665
16666            var parentFormCtrl = formElement.parent().controller('form'),
16667                alias = attr.name || attr.ngForm;
16668
16669            if (alias) {
16670              setter(scope, alias, controller, alias);
16671            }
16672            if (parentFormCtrl) {
16673              formElement.on('$destroy', function() {
16674                parentFormCtrl.$removeControl(controller);
16675                if (alias) {
16676                  setter(scope, alias, undefined, alias);
16677                }
16678                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16679              });
16680            }
16681          }
16682        };
16683      }
16684    };
16685
16686    return formDirective;
16687  }];
16688};
16689
16690var formDirective = formDirectiveFactory();
16691var ngFormDirective = formDirectiveFactory(true);
16692
16693/* global VALID_CLASS: true,
16694    INVALID_CLASS: true,
16695    PRISTINE_CLASS: true,
16696    DIRTY_CLASS: true
16697*/
16698
16699var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16700var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
16701var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16702
16703var inputType = {
16704
16705  /**
16706   * @ngdoc input
16707   * @name input[text]
16708   *
16709   * @description
16710   * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
16711   *
16712   * *NOTE* Not every feature offered is available for all input types.
16713   *
16714   * @param {string} ngModel Assignable angular expression to data-bind to.
16715   * @param {string=} name Property name of the form under which the control is published.
16716   * @param {string=} required Adds `required` validation error key if the value is not entered.
16717   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16718   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16719   *    `required` when you want to data-bind to the `required` attribute.
16720   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16721   *    minlength.
16722   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16723   *    maxlength.
16724   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16725   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16726   *    patterns defined as scope expressions.
16727   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16728   *    interaction with the input element.
16729   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16730   *    This parameter is ignored for input[type=password] controls, which will never trim the
16731   *    input.
16732   *
16733   * @example
16734      <example name="text-input-directive" module="textInputExample">
16735        <file name="index.html">
16736         <script>
16737           angular.module('textInputExample', [])
16738             .controller('ExampleController', ['$scope', function($scope) {
16739               $scope.text = 'guest';
16740               $scope.word = /^\s*\w*\s*$/;
16741             }]);
16742         </script>
16743         <form name="myForm" ng-controller="ExampleController">
16744           Single word: <input type="text" name="input" ng-model="text"
16745                               ng-pattern="word" required ng-trim="false">
16746           <span class="error" ng-show="myForm.input.$error.required">
16747             Required!</span>
16748           <span class="error" ng-show="myForm.input.$error.pattern">
16749             Single word only!</span>
16750
16751           <tt>text = {{text}}</tt><br/>
16752           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16753           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16754           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16755           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16756          </form>
16757        </file>
16758        <file name="protractor.js" type="protractor">
16759          var text = element(by.binding('text'));
16760          var valid = element(by.binding('myForm.input.$valid'));
16761          var input = element(by.model('text'));
16762
16763          it('should initialize to model', function() {
16764            expect(text.getText()).toContain('guest');
16765            expect(valid.getText()).toContain('true');
16766          });
16767
16768          it('should be invalid if empty', function() {
16769            input.clear();
16770            input.sendKeys('');
16771
16772            expect(text.getText()).toEqual('text =');
16773            expect(valid.getText()).toContain('false');
16774          });
16775
16776          it('should be invalid if multi word', function() {
16777            input.clear();
16778            input.sendKeys('hello world');
16779
16780            expect(valid.getText()).toContain('false');
16781          });
16782        </file>
16783      </example>
16784   */
16785  'text': textInputType,
16786
16787
16788  /**
16789   * @ngdoc input
16790   * @name input[number]
16791   *
16792   * @description
16793   * Text input with number validation and transformation. Sets the `number` validation
16794   * error if not a valid number.
16795   *
16796   * @param {string} ngModel Assignable angular expression to data-bind to.
16797   * @param {string=} name Property name of the form under which the control is published.
16798   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16799   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16800   * @param {string=} required Sets `required` validation error key if the value is not entered.
16801   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16802   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16803   *    `required` when you want to data-bind to the `required` attribute.
16804   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16805   *    minlength.
16806   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16807   *    maxlength.
16808   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16809   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16810   *    patterns defined as scope expressions.
16811   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16812   *    interaction with the input element.
16813   *
16814   * @example
16815      <example name="number-input-directive" module="numberExample">
16816        <file name="index.html">
16817         <script>
16818           angular.module('numberExample', [])
16819             .controller('ExampleController', ['$scope', function($scope) {
16820               $scope.value = 12;
16821             }]);
16822         </script>
16823         <form name="myForm" ng-controller="ExampleController">
16824           Number: <input type="number" name="input" ng-model="value"
16825                          min="0" max="99" required>
16826           <span class="error" ng-show="myForm.input.$error.required">
16827             Required!</span>
16828           <span class="error" ng-show="myForm.input.$error.number">
16829             Not valid number!</span>
16830           <tt>value = {{value}}</tt><br/>
16831           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16832           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16833           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16834           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16835          </form>
16836        </file>
16837        <file name="protractor.js" type="protractor">
16838          var value = element(by.binding('value'));
16839          var valid = element(by.binding('myForm.input.$valid'));
16840          var input = element(by.model('value'));
16841
16842          it('should initialize to model', function() {
16843            expect(value.getText()).toContain('12');
16844            expect(valid.getText()).toContain('true');
16845          });
16846
16847          it('should be invalid if empty', function() {
16848            input.clear();
16849            input.sendKeys('');
16850            expect(value.getText()).toEqual('value =');
16851            expect(valid.getText()).toContain('false');
16852          });
16853
16854          it('should be invalid if over max', function() {
16855            input.clear();
16856            input.sendKeys('123');
16857            expect(value.getText()).toEqual('value =');
16858            expect(valid.getText()).toContain('false');
16859          });
16860        </file>
16861      </example>
16862   */
16863  'number': numberInputType,
16864
16865
16866  /**
16867   * @ngdoc input
16868   * @name input[url]
16869   *
16870   * @description
16871   * Text input with URL validation. Sets the `url` validation error key if the content is not a
16872   * valid URL.
16873   *
16874   * @param {string} ngModel Assignable angular expression to data-bind to.
16875   * @param {string=} name Property name of the form under which the control is published.
16876   * @param {string=} required Sets `required` validation error key if the value is not entered.
16877   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16878   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16879   *    `required` when you want to data-bind to the `required` attribute.
16880   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16881   *    minlength.
16882   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16883   *    maxlength.
16884   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16885   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16886   *    patterns defined as scope expressions.
16887   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16888   *    interaction with the input element.
16889   *
16890   * @example
16891      <example name="url-input-directive" module="urlExample">
16892        <file name="index.html">
16893         <script>
16894           angular.module('urlExample', [])
16895             .controller('ExampleController', ['$scope', function($scope) {
16896               $scope.text = 'http://google.com';
16897             }]);
16898         </script>
16899         <form name="myForm" ng-controller="ExampleController">
16900           URL: <input type="url" name="input" ng-model="text" required>
16901           <span class="error" ng-show="myForm.input.$error.required">
16902             Required!</span>
16903           <span class="error" ng-show="myForm.input.$error.url">
16904             Not valid url!</span>
16905           <tt>text = {{text}}</tt><br/>
16906           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16907           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16908           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16909           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16910           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16911          </form>
16912        </file>
16913        <file name="protractor.js" type="protractor">
16914          var text = element(by.binding('text'));
16915          var valid = element(by.binding('myForm.input.$valid'));
16916          var input = element(by.model('text'));
16917
16918          it('should initialize to model', function() {
16919            expect(text.getText()).toContain('http://google.com');
16920            expect(valid.getText()).toContain('true');
16921          });
16922
16923          it('should be invalid if empty', function() {
16924            input.clear();
16925            input.sendKeys('');
16926
16927            expect(text.getText()).toEqual('text =');
16928            expect(valid.getText()).toContain('false');
16929          });
16930
16931          it('should be invalid if not url', function() {
16932            input.clear();
16933            input.sendKeys('box');
16934
16935            expect(valid.getText()).toContain('false');
16936          });
16937        </file>
16938      </example>
16939   */
16940  'url': urlInputType,
16941
16942
16943  /**
16944   * @ngdoc input
16945   * @name input[email]
16946   *
16947   * @description
16948   * Text input with email validation. Sets the `email` validation error key if not a valid email
16949   * address.
16950   *
16951   * @param {string} ngModel Assignable angular expression to data-bind to.
16952   * @param {string=} name Property name of the form under which the control is published.
16953   * @param {string=} required Sets `required` validation error key if the value is not entered.
16954   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16955   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16956   *    `required` when you want to data-bind to the `required` attribute.
16957   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16958   *    minlength.
16959   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16960   *    maxlength.
16961   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16962   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16963   *    patterns defined as scope expressions.
16964   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16965   *    interaction with the input element.
16966   *
16967   * @example
16968      <example name="email-input-directive" module="emailExample">
16969        <file name="index.html">
16970         <script>
16971           angular.module('emailExample', [])
16972             .controller('ExampleController', ['$scope', function($scope) {
16973               $scope.text = '[email protected]';
16974             }]);
16975         </script>
16976           <form name="myForm" ng-controller="ExampleController">
16977             Email: <input type="email" name="input" ng-model="text" required>
16978             <span class="error" ng-show="myForm.input.$error.required">
16979               Required!</span>
16980             <span class="error" ng-show="myForm.input.$error.email">
16981               Not valid email!</span>
16982             <tt>text = {{text}}</tt><br/>
16983             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16984             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16985             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16986             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16987             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16988           </form>
16989         </file>
16990        <file name="protractor.js" type="protractor">
16991          var text = element(by.binding('text'));
16992          var valid = element(by.binding('myForm.input.$valid'));
16993          var input = element(by.model('text'));
16994
16995          it('should initialize to model', function() {
16996            expect(text.getText()).toContain('[email protected]');
16997            expect(valid.getText()).toContain('true');
16998          });
16999
17000          it('should be invalid if empty', function() {
17001            input.clear();
17002            input.sendKeys('');
17003            expect(text.getText()).toEqual('text =');
17004            expect(valid.getText()).toContain('false');
17005          });
17006
17007          it('should be invalid if not email', function() {
17008            input.clear();
17009            input.sendKeys('xxx');
17010
17011            expect(valid.getText()).toContain('false');
17012          });
17013        </file>
17014      </example>
17015   */
17016  'email': emailInputType,
17017
17018
17019  /**
17020   * @ngdoc input
17021   * @name input[radio]
17022   *
17023   * @description
17024   * HTML radio button.
17025   *
17026   * @param {string} ngModel Assignable angular expression to data-bind to.
17027   * @param {string} value The value to which the expression should be set when selected.
17028   * @param {string=} name Property name of the form under which the control is published.
17029   * @param {string=} ngChange Angular expression to be executed when input changes due to user
17030   *    interaction with the input element.
17031   * @param {string} ngValue Angular expression which sets the value to which the expression should
17032   *    be set when selected.
17033   *
17034   * @example
17035      <example name="radio-input-directive" module="radioExample">
17036        <file name="index.html">
17037         <script>
17038           angular.module('radioExample', [])
17039             .controller('ExampleController', ['$scope', function($scope) {
17040               $scope.color = 'blue';
17041               $scope.specialValue = {
17042                 "id": "12345",
17043                 "value": "green"
17044               };
17045             }]);
17046         </script>
17047         <form name="myForm" ng-controller="ExampleController">
17048           <input type="radio" ng-model="color" value="red">  Red <br/>
17049           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
17050           <input type="radio" ng-model="color" value="blue"> Blue <br/>
17051           <tt>color = {{color | json}}</tt><br/>
17052          </form>
17053          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
17054        </file>
17055        <file name="protractor.js" type="protractor">
17056          it('should change state', function() {
17057            var color = element(by.binding('color'));
17058
17059            expect(color.getText()).toContain('blue');
17060
17061            element.all(by.model('color')).get(0).click();
17062
17063            expect(color.getText()).toContain('red');
17064          });
17065        </file>
17066      </example>
17067   */
17068  'radio': radioInputType,
17069
17070
17071  /**
17072   * @ngdoc input
17073   * @name input[checkbox]
17074   *
17075   * @description
17076   * HTML checkbox.
17077   *
17078   * @param {string} ngModel Assignable angular expression to data-bind to.
17079   * @param {string=} name Property name of the form under which the control is published.
17080   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
17081   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
17082   * @param {string=} ngChange Angular expression to be executed when input changes due to user
17083   *    interaction with the input element.
17084   *
17085   * @example
17086      <example name="checkbox-input-directive" module="checkboxExample">
17087        <file name="index.html">
17088         <script>
17089           angular.module('checkboxExample', [])
17090             .controller('ExampleController', ['$scope', function($scope) {
17091               $scope.value1 = true;
17092               $scope.value2 = 'YES'
17093             }]);
17094         </script>
17095         <form name="myForm" ng-controller="ExampleController">
17096           Value1: <input type="checkbox" ng-model="value1"> <br/>
17097           Value2: <input type="checkbox" ng-model="value2"
17098                          ng-true-value="YES" ng-false-value="NO"> <br/>
17099           <tt>value1 = {{value1}}</tt><br/>
17100           <tt>value2 = {{value2}}</tt><br/>
17101          </form>
17102        </file>
17103        <file name="protractor.js" type="protractor">
17104          it('should change state', function() {
17105            var value1 = element(by.binding('value1'));
17106            var value2 = element(by.binding('value2'));
17107
17108            expect(value1.getText()).toContain('true');
17109            expect(value2.getText()).toContain('YES');
17110
17111            element(by.model('value1')).click();
17112            element(by.model('value2')).click();
17113
17114            expect(value1.getText()).toContain('false');
17115            expect(value2.getText()).toContain('NO');
17116          });
17117        </file>
17118      </example>
17119   */
17120  'checkbox': checkboxInputType,
17121
17122  'hidden': noop,
17123  'button': noop,
17124  'submit': noop,
17125  'reset': noop,
17126  'file': noop
17127};
17128
17129// A helper function to call $setValidity and return the value / undefined,
17130// a pattern that is repeated a lot in the input validation logic.
17131function validate(ctrl, validatorName, validity, value){
17132  ctrl.$setValidity(validatorName, validity);
17133  return validity ? value : undefined;
17134}
17135
17136function testFlags(validity, flags) {
17137  var i, flag;
17138  if (flags) {
17139    for (i=0; i<flags.length; ++i) {
17140      flag = flags[i];
17141      if (validity[flag]) {
17142        return true;
17143      }
17144    }
17145  }
17146  return false;
17147}
17148
17149// Pass validity so that behaviour can be mocked easier.
17150function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
17151  if (isObject(validity)) {
17152    ctrl.$$hasNativeValidators = true;
17153    var validator = function(value) {
17154      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
17155      // perform the required validation)
17156      if (!ctrl.$error[validatorName] &&
17157          !testFlags(validity, ignoreFlags) &&
17158          testFlags(validity, badFlags)) {
17159        ctrl.$setValidity(validatorName, false);
17160        return;
17161      }
17162      return value;
17163    };
17164    ctrl.$parsers.push(validator);
17165  }
17166}
17167
17168function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17169  var validity = element.prop(VALIDITY_STATE_PROPERTY);
17170  var placeholder = element[0].placeholder, noevent = {};
17171  var type = lowercase(element[0].type);
17172  ctrl.$$validityState = validity;
17173
17174  // In composition mode, users are still inputing intermediate text buffer,
17175  // hold the listener until composition is done.
17176  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
17177  if (!$sniffer.android) {
17178    var composing = false;
17179
17180    element.on('compositionstart', function(data) {
17181      composing = true;
17182    });
17183
17184    element.on('compositionend', function() {
17185      composing = false;
17186      listener();
17187    });
17188  }
17189
17190  var listener = function(ev) {
17191    if (composing) return;
17192    var value = element.val();
17193
17194    // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
17195    // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
17196    // IE also sends input events for other non-input-related things, (such as focusing on a
17197    // form control), so this change is not entirely enough to solve this.
17198    if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
17199      placeholder = element[0].placeholder;
17200      return;
17201    }
17202
17203    // By default we will trim the value
17204    // If the attribute ng-trim exists we will avoid trimming
17205    // If input type is 'password', the value is never trimmed
17206    if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
17207      value = trim(value);
17208    }
17209
17210    // If a control is suffering from bad input, browsers discard its value, so it may be
17211    // necessary to revalidate even if the control's value is the same empty value twice in
17212    // a row.
17213    var revalidate = validity && ctrl.$$hasNativeValidators;
17214    if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
17215      if (scope.$root.$$phase) {
17216        ctrl.$setViewValue(value);
17217      } else {
17218        scope.$apply(function() {
17219          ctrl.$setViewValue(value);
17220        });
17221      }
17222    }
17223  };
17224
17225  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
17226  // input event on backspace, delete or cut
17227  if ($sniffer.hasEvent('input')) {
17228    element.on('input', listener);
17229  } else {
17230    var timeout;
17231
17232    var deferListener = function() {
17233      if (!timeout) {
17234        timeout = $browser.defer(function() {
17235          listener();
17236          timeout = null;
17237        });
17238      }
17239    };
17240
17241    element.on('keydown', function(event) {
17242      var key = event.keyCode;
17243
17244      // ignore
17245      //    command            modifiers                   arrows
17246      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
17247
17248      deferListener();
17249    });
17250
17251    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
17252    if ($sniffer.hasEvent('paste')) {
17253      element.on('paste cut', deferListener);
17254    }
17255  }
17256
17257  // if user paste into input using mouse on older browser
17258  // or form autocomplete on newer browser, we need "change" event to catch it
17259  element.on('change', listener);
17260
17261  ctrl.$render = function() {
17262    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
17263  };
17264
17265  // pattern validator
17266  var pattern = attr.ngPattern,
17267      patternValidator,
17268      match;
17269
17270  if (pattern) {
17271    var validateRegex = function(regexp, value) {
17272      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
17273    };
17274    match = pattern.match(/^\/(.*)\/([gim]*)$/);
17275    if (match) {
17276      pattern = new RegExp(match[1], match[2]);
17277      patternValidator = function(value) {
17278        return validateRegex(pattern, value);
17279      };
17280    } else {
17281      patternValidator = function(value) {
17282        var patternObj = scope.$eval(pattern);
17283
17284        if (!patternObj || !patternObj.test) {
17285          throw minErr('ngPattern')('noregexp',
17286            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
17287            patternObj, startingTag(element));
17288        }
17289        return validateRegex(patternObj, value);
17290      };
17291    }
17292
17293    ctrl.$formatters.push(patternValidator);
17294    ctrl.$parsers.push(patternValidator);
17295  }
17296
17297  // min length validator
17298  if (attr.ngMinlength) {
17299    var minlength = int(attr.ngMinlength);
17300    var minLengthValidator = function(value) {
17301      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
17302    };
17303
17304    ctrl.$parsers.push(minLengthValidator);
17305    ctrl.$formatters.push(minLengthValidator);
17306  }
17307
17308  // max length validator
17309  if (attr.ngMaxlength) {
17310    var maxlength = int(attr.ngMaxlength);
17311    var maxLengthValidator = function(value) {
17312      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
17313    };
17314
17315    ctrl.$parsers.push(maxLengthValidator);
17316    ctrl.$formatters.push(maxLengthValidator);
17317  }
17318}
17319
17320var numberBadFlags = ['badInput'];
17321
17322function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17323  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17324
17325  ctrl.$parsers.push(function(value) {
17326    var empty = ctrl.$isEmpty(value);
17327    if (empty || NUMBER_REGEXP.test(value)) {
17328      ctrl.$setValidity('number', true);
17329      return value === '' ? null : (empty ? value : parseFloat(value));
17330    } else {
17331      ctrl.$setValidity('number', false);
17332      return undefined;
17333    }
17334  });
17335
17336  addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
17337
17338  ctrl.$formatters.push(function(value) {
17339    return ctrl.$isEmpty(value) ? '' : '' + value;
17340  });
17341
17342  if (attr.min) {
17343    var minValidator = function(value) {
17344      var min = parseFloat(attr.min);
17345      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
17346    };
17347
17348    ctrl.$parsers.push(minValidator);
17349    ctrl.$formatters.push(minValidator);
17350  }
17351
17352  if (attr.max) {
17353    var maxValidator = function(value) {
17354      var max = parseFloat(attr.max);
17355      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
17356    };
17357
17358    ctrl.$parsers.push(maxValidator);
17359    ctrl.$formatters.push(maxValidator);
17360  }
17361
17362  ctrl.$formatters.push(function(value) {
17363    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
17364  });
17365}
17366
17367function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17368  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17369
17370  var urlValidator = function(value) {
17371    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
17372  };
17373
17374  ctrl.$formatters.push(urlValidator);
17375  ctrl.$parsers.push(urlValidator);
17376}
17377
17378function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17379  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17380
17381  var emailValidator = function(value) {
17382    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
17383  };
17384
17385  ctrl.$formatters.push(emailValidator);
17386  ctrl.$parsers.push(emailValidator);
17387}
17388
17389function radioInputType(scope, element, attr, ctrl) {
17390  // make the name unique, if not defined
17391  if (isUndefined(attr.name)) {
17392    element.attr('name', nextUid());
17393  }
17394
17395  element.on('click', function() {
17396    if (element[0].checked) {
17397      scope.$apply(function() {
17398        ctrl.$setViewValue(attr.value);
17399      });
17400    }
17401  });
17402
17403  ctrl.$render = function() {
17404    var value = attr.value;
17405    element[0].checked = (value == ctrl.$viewValue);
17406  };
17407
17408  attr.$observe('value', ctrl.$render);
17409}
17410
17411function checkboxInputType(scope, element, attr, ctrl) {
17412  var trueValue = attr.ngTrueValue,
17413      falseValue = attr.ngFalseValue;
17414
17415  if (!isString(trueValue)) trueValue = true;
17416  if (!isString(falseValue)) falseValue = false;
17417
17418  element.on('click', function() {
17419    scope.$apply(function() {
17420      ctrl.$setViewValue(element[0].checked);
17421    });
17422  });
17423
17424  ctrl.$render = function() {
17425    element[0].checked = ctrl.$viewValue;
17426  };
17427
17428  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
17429  ctrl.$isEmpty = function(value) {
17430    return value !== trueValue;
17431  };
17432
17433  ctrl.$formatters.push(function(value) {
17434    return value === trueValue;
17435  });
17436
17437  ctrl.$parsers.push(function(value) {
17438    return value ? trueValue : falseValue;
17439  });
17440}
17441
17442
17443/**
17444 * @ngdoc directive
17445 * @name textarea
17446 * @restrict E
17447 *
17448 * @description
17449 * HTML textarea element control with angular data-binding. The data-binding and validation
17450 * properties of this element are exactly the same as those of the
17451 * {@link ng.directive:input input element}.
17452 *
17453 * @param {string} ngModel Assignable angular expression to data-bind to.
17454 * @param {string=} name Property name of the form under which the control is published.
17455 * @param {string=} required Sets `required` validation error key if the value is not entered.
17456 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17457 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17458 *    `required` when you want to data-bind to the `required` attribute.
17459 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17460 *    minlength.
17461 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17462 *    maxlength.
17463 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17464 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17465 *    patterns defined as scope expressions.
17466 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17467 *    interaction with the input element.
17468 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17469 */
17470
17471
17472/**
17473 * @ngdoc directive
17474 * @name input
17475 * @restrict E
17476 *
17477 * @description
17478 * HTML input element control with angular data-binding. Input control follows HTML5 input types
17479 * and polyfills the HTML5 validation behavior for older browsers.
17480 *
17481 * *NOTE* Not every feature offered is available for all input types.
17482 *
17483 * @param {string} ngModel Assignable angular expression to data-bind to.
17484 * @param {string=} name Property name of the form under which the control is published.
17485 * @param {string=} required Sets `required` validation error key if the value is not entered.
17486 * @param {boolean=} ngRequired Sets `required` attribute if set to true
17487 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17488 *    minlength.
17489 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17490 *    maxlength.
17491 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17492 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17493 *    patterns defined as scope expressions.
17494 * @param {string=} ngChange Angular expression to be executed when input changes due to user
17495 *    interaction with the input element.
17496 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17497 *    This parameter is ignored for input[type=password] controls, which will never trim the
17498 *    input.
17499 *
17500 * @example
17501    <example name="input-directive" module="inputExample">
17502      <file name="index.html">
17503       <script>
17504          angular.module('inputExample', [])
17505            .controller('ExampleController', ['$scope', function($scope) {
17506              $scope.user = {name: 'guest', last: 'visitor'};
17507            }]);
17508       </script>
17509       <div ng-controller="ExampleController">
17510         <form name="myForm">
17511           User name: <input type="text" name="userName" ng-model="user.name" required>
17512           <span class="error" ng-show="myForm.userName.$error.required">
17513             Required!</span><br>
17514           Last name: <input type="text" name="lastName" ng-model="user.last"
17515             ng-minlength="3" ng-maxlength="10">
17516           <span class="error" ng-show="myForm.lastName.$error.minlength">
17517             Too short!</span>
17518           <span class="error" ng-show="myForm.lastName.$error.maxlength">
17519             Too long!</span><br>
17520         </form>
17521         <hr>
17522         <tt>user = {{user}}</tt><br/>
17523         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
17524         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
17525         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
17526         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
17527         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
17528         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
17529         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
17530         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
17531       </div>
17532      </file>
17533      <file name="protractor.js" type="protractor">
17534        var user = element(by.binding('{{user}}
vendor: 2,296 bytes, lines 17534-17588
17534'));
17535        var userNameValid = element(by.binding('myForm.userName.$valid'));
17536        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
17537        var lastNameError = element(by.binding('myForm.lastName.$error'));
17538        var formValid = element(by.binding('myForm.$valid'));
17539        var userNameInput = element(by.model('user.name'));
17540        var userLastInput = element(by.model('user.last'));
17541
17542        it('should initialize to model', function() {
17543          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
17544          expect(userNameValid.getText()).toContain('true');
17545          expect(formValid.getText()).toContain('true');
17546        });
17547
17548        it('should be invalid if empty when required', function() {
17549          userNameInput.clear();
17550          userNameInput.sendKeys('');
17551
17552          expect(user.getText()).toContain('{"last":"visitor"}');
17553          expect(userNameValid.getText()).toContain('false');
17554          expect(formValid.getText()).toContain('false');
17555        });
17556
17557        it('should be valid if empty when min length is set', function() {
17558          userLastInput.clear();
17559          userLastInput.sendKeys('');
17560
17561          expect(user.getText()).toContain('{"name":"guest","last":""}');
17562          expect(lastNameValid.getText()).toContain('true');
17563          expect(formValid.getText()).toContain('true');
17564        });
17565
17566        it('should be invalid if less than required min length', function() {
17567          userLastInput.clear();
17568          userLastInput.sendKeys('xx');
17569
17570          expect(user.getText()).toContain('{"name":"guest"}');
17571          expect(lastNameValid.getText()).toContain('false');
17572          expect(lastNameError.getText()).toContain('minlength');
17573          expect(formValid.getText()).toContain('false');
17574        });
17575
17576        it('should be invalid if longer than max length', function() {
17577          userLastInput.clear();
17578          userLastInput.sendKeys('some ridiculously long name');
17579
17580          expect(user.getText()).toContain('{"name":"guest"}');
17581          expect(lastNameValid.getText()).toContain('false');
17582          expect(lastNameError.getText()).toContain('maxlength');
17583          expect(formValid.getText()).toContain('false');
17584        });
17585      </file>
17586    </example>
17587 */
17588var inputDirective = ['$browser', '$sniffer', 
17588function($browser, $sniffer) {
17589  return {
17590    restrict: 'E',
17591    require: '?ngModel',
17592    link: function(scope, element, attr, ctrl) {
17593      if (ctrl) {
17594        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17595                                                            $browser);
17596      }
17597    }
17598  };
17599}];
17600
17601var VALID_CLASS = 'ng-valid',
17602    INVALID_CLASS = 'ng-invalid',
17603    PRISTINE_CLASS = 'ng-pristine',
17604    DIRTY_CLASS = 'ng-dirty';
17605
17606/**
17607 * @ngdoc type
17608 * @name ngModel.NgModelController
17609 *
17610 * @property {string} $viewValue Actual string value in the view.
17611 * @property {*} $modelValue The value in the model, that the control is bound to.
17612 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17613       the control reads value from the DOM.  Each function is called, in turn, passing the value
17614       through to the next. The last return value is used to populate the model.
17615       Used to sanitize / convert the value as well as validation. For validation,
17616       the parsers should update the validity state using
17617       {@link ngModel.NgModelController#$setValidity $setValidity()},
17618       and return `undefined` for invalid values.
17619
17620 *
17621 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17622       the model value changes. Each function is called, in turn, passing the value through to the
17623       next. Used to format / convert values for display in the control and validation.
17624 * ```js
17625 * function formatter(value) {
17626 *   if (value) {
17627 *     return value.toUpperCase();
17628 *   }
17629 * }
17630 * ngModel.$formatters.push(formatter);
17631 * ```
17632 *
17633 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17634 *     view value has changed. It is called with no arguments, and its return value is ignored.
17635 *     This can be used in place of additional $watches against the model value.
17636 *
17637 * @property {Object} $error An object hash with all errors as keys.
17638 *
17639 * @property {boolean} $pristine True if user has not interacted with the control yet.
17640 * @property {boolean} $dirty True if user has already interacted with the control.
17641 * @property {boolean} $valid True if there is no error.
17642 * @property {boolean} $invalid True if at least one error on the control.
17643 *
17644 * @description
17645 *
17646 * `NgModelController` provides API for the `ng-model` directive. The controller contains
17647 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17648 * purposefully does not contain any logic which deals with DOM rendering or listening to
17649 * DOM events. Such DOM related logic should be provided by other directives which make use of
17650 * `NgModelController` for data-binding.
17651 *
17652 * ## Custom Control Example
17653 * This example shows how to use `NgModelController` with a custom control to achieve
17654 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17655 * collaborate together to achieve the desired result.
17656 *
17657 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17658 * contents be edited in place by the user.  This will not work on older browsers.
17659 *
17660 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
17661 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
17662 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
17663 * that content using the `$sce` service.
17664 *
17665 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
17666    <file name="style.css">
17667      [contenteditable] {
17668        border: 1px solid black;
17669        background-color: white;
17670        min-height: 20px;
17671      }
17672
17673      .ng-invalid {
17674        border: 1px solid red;
17675      }
17676
17677    </file>
17678    <file name="script.js">
17679      angular.module('customControl', ['ngSanitize']).
17680        directive('contenteditable', ['$sce', function($sce) {
17681          return {
17682            restrict: 'A', // only activate on element attribute
17683            require: '?ngModel', // get a hold of NgModelController
17684            link: function(scope, element, attrs, ngModel) {
17685              if(!ngModel) return; // do nothing if no ng-model
17686
17687              // Specify how UI should be updated
17688              ngModel.$render = function() {
17689                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
17690              };
17691
17692              // Listen for change events to enable binding
17693              element.on('blur keyup change', function() {
17694                scope.$evalAsync(read);
17695              });
17696              read(); // initialize
17697
17698              // Write data to the model
17699              function read() {
17700                var html = element.html();
17701                // When we clear the content editable the browser leaves a <br> behind
17702                // If strip-br attribute is provided then we strip this out
17703                if( attrs.stripBr && html == '<br>' ) {
17704                  html = '';
17705                }
17706                ngModel.$setViewValue(html);
17707              }
17708            }
17709          };
17710        }]);
17711    </file>
17712    <file name="index.html">
17713      <form name="myForm">
17714       <div contenteditable
17715            name="myWidget" ng-model="userContent"
17716            strip-br="true"
17717            required>Change me!</div>
17718        <span ng-show="myForm.myWidget.$error.required">Required!</span>
17719       <hr>
17720       <textarea ng-model="userContent"></textarea>
17721      </form>
17722    </file>
17723    <file name="protractor.js" type="protractor">
17724    it('should data-bind and become invalid', function() {
17725      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17726        // SafariDriver can't handle contenteditable
17727        // and Firefox driver can't clear contenteditables very well
17728        return;
17729      }
17730      var contentEditable = element(by.css('[contenteditable]'));
17731      var content = 'Change me!';
17732
17733      expect(contentEditable.getText()).toEqual(content);
17734
17735      contentEditable.clear();
17736      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17737      expect(contentEditable.getText()).toEqual('');
17738      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17739    });
17740    </file>
17741 * </example>
17742 *
17743 *
17744 */
17745var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17746    function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17747  this.$viewValue = Number.NaN;
17748  this.$modelValue = Number.NaN;
17749  this.$parsers = [];
17750  this.$formatters = [];
17751  this.$viewChangeListeners = [];
17752  this.$pristine = true;
17753  this.$dirty = false;
17754  this.$valid = true;
17755  this.$invalid = false;
17756  this.$name = $attr.name;
17757
17758  var ngModelGet = $parse($attr.ngModel),
17759      ngModelSet = ngModelGet.assign;
17760
17761  if (!ngModelSet) {
17762    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17763        $attr.ngModel, startingTag($element));
17764  }
17765
17766  /**
17767   * @ngdoc method
17768   * @name ngModel.NgModelController#$render
17769   *
17770   * @description
17771   * Called when the view needs to be updated. It is expected that the user of the ng-model
17772   * directive will implement this method.
17773   */
17774  this.$render = noop;
17775
17776  /**
17777   * @ngdoc method
17778   * @name ngModel.NgModelController#$isEmpty
17779   *
17780   * @description
17781   * This is called when we need to determine if the value of the input is empty.
17782   *
17783   * For instance, the required directive does this to work out if the input has data or not.
17784   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17785   *
17786   * You can override this for input directives whose concept of being empty is different to the
17787   * default. The `checkboxInputType` directive does this because in its case a value of `false`
17788   * implies empty.
17789   *
17790   * @param {*} value Reference to check.
17791   * @returns {boolean} True if `value` is empty.
17792   */
17793  this.$isEmpty = function(value) {
17794    return isUndefined(value) || value === '' || value === null || value !== value;
17795  };
17796
17797  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17798      invalidCount = 0, // used to easily determine if we are valid
17799      $error = this.$error = {}; // keep invalid keys here
17800
17801
17802  // Setup initial state of the control
17803  $element.addClass(PRISTINE_CLASS);
17804  toggleValidCss(true);
17805
17806  // convenience method for easy toggling of classes
17807  function toggleValidCss(isValid, validationErrorKey) {
17808    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17809    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17810    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17811  }
17812
17813  /**
17814   * @ngdoc method
17815   * @name ngModel.NgModelController#$setValidity
17816   *
17817   * @description
17818   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17819   * does not notify form if given validator is already marked as invali
17819d).
17820   *
17821   * This method should be called by validators - i.e. the parser or formatter functions.
17822   *
17823   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17824   *        to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
17825   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17826   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17827   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17828   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17829   */
17830  this.$setValidity = function(validationErrorKey, isValid) {
17831    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17832    // jshint -W018
17833    if ($error[validationErrorKey] === !isValid) return;
17834    // jshint +W018
17835
17836    if (isValid) {
17837      if ($error[validationErrorKey]) invalidCount--;
17838      if (!invalidCount) {
17839        toggleValidCss(true);
17840        this.$valid = true;
17841        this.$invalid = false;
17842      }
17843    } else {
17844      toggleValidCss(false);
17845      this.$invalid = true;
17846      this.$valid = false;
17847      invalidCount++;
17848    }
17849
17850    $error[validationErrorKey] = !isValid;
17851    toggleValidCss(isValid, validationErrorKey);
17852
17853    parentForm.$setValidity(validationErrorKey, isValid, this);
17854  };
17855
17856  /**
17857   * @ngdoc method
17858   * @name ngModel.NgModelController#$setPristine
17859   *
17860   * @description
17861   * Sets the control to its pristine state.
17862   *
17863   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17864   * state (ng-pristine class).
17865   */
17866  this.$setPristine = function () {
17867    this.$dirty = false;
17868    this.$pristine = true;
17869    $animate.removeClass($element, DIRTY_CLASS);
17870    $animate.addClass($element, PRISTINE_CLASS);
17871  };
17872
17873  /**
17874   * @ngdoc method
17875   * @name ngModel.NgModelController#$setViewValue
17876   *
17877   * @description
17878   * Update the view value.
17879   *
17880   * This method should be called when the view value changes, typically from within a DOM event handler.
17881   * For example {@link ng.directive:input input} and
17882   * {@link ng.directive:select select} directives call it.
17883   *
17884   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17885   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17886   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17887   *
17888   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17889   *
17890   * Note that calling this function does not trigger a `$digest`.
17891   *
17892   * @param {string} value Value from the view.
17893   */
17894  this.$setViewValue = function(value) {
17895    this.$viewValue = value;
17896
17897    // change to dirty
17898    if (this.$pristine) {
17899      this.$dirty = true;
17900      this.$pristine = false;
17901      $animate.removeClass($element, PRISTINE_CLASS);
17902      $animate.addClass($element, DIRTY_CLASS);
17903      parentForm.$setDirty();
17904    }
17905
17906    forEach(this.$parsers, function(fn) {
17907      value = fn(value);
17908    });
17909
17910    if (this.$modelValue !== value) {
17911      this.$modelValue = value;
17912      ngModelSet($scope, value);
17913      forEach(this.$viewChangeListeners, function(listener) {
17914        try {
17915          listener();
17916        } catch(e) {
17917          $exceptionHandler(e);
17918        }
17919      });
17920    }
17921  };
17922
17923  // model -> value
17924  var ctrl = this;
17925
17926  $scope.$watch(function ngModelWatch() {
17927    var value = ngModelGet($scope);
17928
17929    // if scope model value and ngModel value are out of sync
17930    if (ctrl.$modelValue !== value) {
17931
17932      var formatters = ctrl.$formatters,
17933          idx = formatters.length;
17934
17935      ctrl.$modelValue = value;
17936      while(idx--) {
17937        value = formatters[idx](value);
17938      }
17939
17940      if (ctrl.$viewValue !== value) {
17941        ctrl.$viewValue = value;
17942        ctrl.$render();
17943      }
17944    }
17945
17946    return value;
17947  });
17948}];
17949
17950
17951/**
17952 * @ngdoc directive
17953 * @name ngModel
17954 *
17955 * @element input
17956 *
17957 * @description
17958 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17959 * property on the scope using {@link ngModel.NgModelController NgModelController},
17960 * which is created and exposed by this directive.
17961 *
17962 * `ngModel` is responsible for:
17963 *
17964 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17965 *   require.
17966 * - Providing validation behavior (i.e. required, number, email, url).
17967 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17968 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17969 * - Registering the control with its parent {@link ng.directive:form form}.
17970 *
17971 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17972 * current scope. If the property doesn't already exist on this scope, it will be created
17973 * implicitly and added to the scope.
17974 *
17975 * For best practices on using `ngModel`, see:
17976 *
17977 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
17978 *
17979 * For basic examples, how to use `ngModel`, see:
17980 *
17981 *  - {@link ng.directive:input input}
17982 *    - {@link input[text] text}
17983 *    - {@link input[checkbox] checkbox}
17984 *    - {@link input[radio] radio}
17985 *    - {@link input[number] number}
17986 *    - {@link input[email] email}
17987 *    - {@link input[url] url}
17988 *  - {@link ng.directive:select select}
17989 *  - {@link ng.directive:textarea textarea}
17990 *
17991 * # CSS classes
17992 * The following CSS classes are added and removed on the associated input/select/textarea element
17993 * depending on the validity of the model.
17994 *
17995 *  - `ng-valid` is set if the model is valid.
17996 *  - `ng-invalid` is set if the model is invalid.
17997 *  - `ng-pristine` is set if the model is pristine.
17998 *  - `ng-dirty` is set if the model is dirty.
17999 *
18000 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
18001 *
18002 * ## Animation Hooks
18003 *
18004 * Animations within models are triggered when any of the associated CSS classes are added and removed
18005 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
18006 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
18007 * The animations that are triggered within ngModel are similar to how they work in ngClass and
18008 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
18009 *
18010 * The following example shows a simple way to utilize CSS transitions to style an input element
18011 * that has been rendered as invalid after it has been validated:
18012 *
18013 * <pre>
18014 * //be sure to include ngAnimate as a module to hook into more
18015 * //advanced animations
18016 * .my-input {
18017 *   transition:0.5s linear all;
18018 *   background: white;
18019 * }
18020 * .my-input.ng-invalid {
18021 *   background: red;
18022 *   color:white;
18023 * }
18024 * </pre>
18025 *
18026 * @example
18027 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
18028     <file name="index.html">
18029       <script>
18030        angular.module('inputExample', [])
18031          .controller('ExampleController', ['$scope', function($scope) {
18032            $scope.val = '1';
18033          }]);
18034       </script>
18035       <style>
18036         .my-input {
18037           -webkit-transition:all linear 0.5s;
18038           transition:all linear 0.5s;
18039           background: transparent;
18040         }
18041         .my-input.ng-invalid {
18042           color:white;
18043           background: red;
18044         }
18045       </style>
18046       Update input to see transitions when valid/invalid.
18047       Integer is a valid value.
18048       <form name="testForm" ng-controller="ExampleController">
18049         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
18050       </form>
18051     </file>
18052 * </example>
18053 */
18054var ngModelDirective = function() {
18055  return {
18056    require: ['ngModel', '^?form'],
18057    controller: NgModelController,
18058    link: function(scope, element, attr, ctrls) {
18059      // notify others, especially parent forms
18060
18061      var modelCtrl = ctrls[0],
18062          formCtrl = ctrls[1] || nullFormCtrl;
18063
18064      formCtrl.$addControl(modelCtrl);
18065
18066      scope.$on('$destroy', function() {
18067        formCtrl.$removeControl(modelCtrl);
18068      });
18069    }
18070  };
18071};
18072
18073
18074/**
18075 * @ngdoc directive
18076 * @name ngChange
18077 *
18078 * @description
18079 * Evaluate the given expression when the user changes the input.
18080 * The expression is evaluated immediately, unlike the JavaScript onchange event
18081 * which only triggers at the end of a change (usually, when the user leaves the
18082 * form element or presses the return key).
18083 * The expression is not evaluated when the value change is coming from the model.
18084 *
18085 * Note, this directive requires `ngModel` to be present.
18086 *
18087 * @element input
18088 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
18089 * in input value.
18090 *
18091 * @example
18092 * <example name="ngChange-directive" module="changeExample">
18093 *   <file name="index.html">
18094 *     <script>
18095 *       angular.module('changeExample', [])
18096 *         .controller('ExampleController', ['$scope', function($scope) {
18097 *           $scope.counter = 0;
18098 *           $scope.change = function() {
18099 *             $scope.counter++;
18100 *           };
18101 *         }]);
18102 *     </script>
18103 *     <div ng-controller="ExampleController">
18104 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
18105 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
18106 *       <label for="ng-change-example2">Confirmed</label><br />
18107 *       <tt>debug = {{confirmed}}</tt><br/>
18108 *       <tt>counter = {{counter}}</tt><br/>
18109 *     </div>
18110 *   </file>
18111 *   <file name="protractor.js" type="protractor">
18112 *     var counter = element(by.binding('counter'));
18113 *     var debug = element(by.binding('confirmed'));
18114 *
18115 *     it('should evaluate the expression if changing from view', function() {
18116 *       expect(counter.getText()).toContain('0');
18117 *
18118 *       element(by.id('ng-change-example1')).click();
18119 *
18120 *       expect(counter.getText()).toContain('1');
18121 *       expect(debug.getText()).toContain('true');
18122 *     });
18123 *
18124 *     it('should not evaluate the expression if changing from model', function() {
18125 *       element(by.id('ng-change-example2')).click();
18126
18127 *       expect(counter.getText()).toContain('0');
18128 *       expect(debug.getText()).toContain('true');
18129 *     });
18130 *   </file>
18131 * </example>
18132 */
18133var ngChangeDirective = valueFn({
18134  require: 'ngModel',
18135  link: function(scope, element, attr, ctrl) {
18136    ctrl.$viewChangeListeners.push(function() {
18137      scope.$eval(attr.ngChange);
18138    });
18139  }
18140});
18141
18142
18143var requiredDirective = function() {
18144  return {
18145    require: '?ngModel',
18146    link: function(scope, elm, attr, ctrl) {
18147      if (!ctrl) return;
18148      attr.required = true; // force truthy in case we are on non input element
18149
18150      var validator = function(value) {
18151        if (attr.required && ctrl.$isEmpty(value)) {
18152          ctrl.$setValidity('required', false);
18153          return;
18154        } else {
18155          ctrl.$setValidity('required', true);
18156          return value;
18157        }
18158      };
18159
18160      ctrl.$formatters.push(validator);
18161      ctrl.$parsers.unshift(validator);
18162
18163      attr.$observe('required', function() {
18164        validator(ctrl.$viewValue);
18165      });
18166    }
18167  };
18168};
18169
18170
18171/**
18172 * @ngdoc directive
18173 * @name ngList
18174 *
18175 * @description
18176 * Text input that converts between a delimited string and an array of strings. The delimiter
18177 * can be a fixed string (by default a comma) or a regular expression.
18178 *
18179 * @element input
18180 * @param {string=} ngList optional delimiter that should be used to split the value. If
18181 *   specified in form `/something/` then the value will be converted into a regular expression.
18182 *
18183 * @example
18184    <example name="ngList-directive" module="listExample">
18185      <file name="index.html">
18186       <script>
18187         angular.module('listExample', [])
18188           .controller('ExampleController', ['$scope', function($scope) {
18189             $scope.names = ['igor', 'misko', 'vojta'];
18190           }]);
18191       </script>
18192       <form name="myForm" ng-controller="ExampleController">
18193         List: <input name="namesInput" ng-model="names" ng-list required>
18194         <span class="error" ng-show="myForm.namesInput.$error.required">
18195           Required!</span>
18196         <br>
18197         <tt>names = {{names}}</tt><br/>
18198         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
18199         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
18200         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18201         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18202        </form>
18203      </file>
18204      <file name="protractor.js" type="protractor">
18205        var listInput = element(by.model('names'));
18206        var names = element(by.binding('{{names}}'));
18207        var valid = element(by.binding('myForm.namesInput.$valid'));
18208        var error = element(by.css('span.error'));
18209
18210        it('should initialize to model', function() {
18211          expect(names.getText()).toContain('["igor","misko","vojta"]');
18212          expect(valid.getText()).toContain('true');
18213          expect(error.getCssValue('display')).toBe('none');
18214        });
18215
18216        it('should be invalid if empty', function() {
18217          listInput.clear();
18218          listInput.sendKeys('');
18219
18220          expect(names.getText()).toContain('');
18221          expect(valid.getText()).toContain('false');
18222          expect(error.getCssValue('display')).not.toBe('none');        });
18223      </file>
18224    </example>
18225 */
18226var ngListDirective = function() {
18227  return {
18228    require: 'ngModel',
18229    link: function(scope, element, attr, ctrl) {
18230      var match = /\/(.*)\//.exec(attr.ngList),
18231          separator = match && new RegExp(match[1]) || attr.ngList || ',';
18232
18233      var parse = function(viewValue) {
18234        // If the viewValue is invalid (say required but empty) it will be `undefined`
18235        if (isUndefined(viewValue)) return;
18236
18237        var list = [];
18238
18239        if (viewValue) {
18240          forEach(viewValue.split(separator), function(value) {
18241            if (value) list.push(trim(value));
18242          });
18243        }
18244
18245        return list;
18246      };
18247
18248      ctrl.$parsers.push(parse);
18249      ctrl.$formatters.push(function(value) {
18250        if (isArray(value)) {
18251          return value.join(', ');
18252        }
18253
18254        return undefined;
18255      });
18256
18257      // Override the standard $isEmpty because an empty array means the input is empty.
18258      ctrl.$isEmpty = function(value) {
18259        return !value || !value.length;
18260      };
18261    }
18262  };
18263};
18264
18265
18266var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
18267/**
18268 * @ngdoc directive
18269 * @name ngValue
18270 *
18271 * @description
18272 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
18273 * that when the element is selected, the `ngModel` of that element is set to the
18274 * bound value.
18275 *
18276 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
18277 * shown below.
18278 *
18279 * @element input
18280 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
18281 *   of the `input` element
18282 *
18283 * @example
18284    <example name="ngValue-directive" module="valueExample">
18285      <file name="index.html">
18286       <script>
18287          angular.module('valueExample', [])
18288            .controller('ExampleController', ['$scope', function($scope) {
18289              $scope.names = ['pizza', 'unicorns', 'robots'];
18290              $scope.my = { favorite: 'unicorns' };
18291            }]);
18292       </script>
18293        <form ng-controller="ExampleController">
18294          <h2>Which is your favorite?</h2>
18295            <label ng-repeat="name in names" for="{{name}}">
18296              {{name}}
18297              <input type="radio"
18298                     ng-model="my.favorite"
18299                     ng-value="name"
18300                     id="{{name}}"
18301                     name="favorite">
18302            </label>
18303          <div>You chose {{my.favorite}}</div>
18304        </form>
18305      </file>
18306      <file name="protractor.js" type="protractor">
18307        var favorite = element(by.binding('my.favorite'));
18308
18309        it('should initialize to model', function() {
18310          expect(favorite.getText()).toContain('unicorns');
18311        });
18312        it('should bind the values to the inputs', function() {
18313          element.all(by.model('my.favorite')).get(0).click();
18314          expect(favorite.getText()).toContain('pizza');
18315        });
18316      </file>
18317    </example>
18318 */
18319var ngValueDirective = function() {
18320  return {
18321    priority: 100,
18322    compile: function(tpl, tplAttr) {
18323      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
18324        return function ngValueConstantLink(scope, elm, attr) {
18325          attr.$set('value', scope.$eval(attr.ngValue));
18326        };
18327      } else {
18328        return function ngValueLink(scope, elm, attr) {
18329          scope.$watch(attr.ngValue, function valueWatchAction(value) {
18330            attr.$set('value', value);
18331          });
18332        };
18333      }
18334    }
18335  };
18336};
18337
18338/**
18339 * @ngdoc directive
18340 * @name ngBind
18341 * @restrict AC
18342 *
18343 * @description
18344 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
18345 * with the value of a given expression, and to update the text content when the value of that
18346 * expression changes.
18347 *
18348 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
18349 * `{{ expression }}` which is similar but less verbose.
18350 *
18351 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
18352 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
18353 * element attribute, it makes the bindings invisible to the user while the page is loading.
18354 *
18355 * An alternative solution to this problem would be using the
18356 * {@link ng.directive:ngCloak ngCloak} directive.
18357 *
18358 *
18359 * @element ANY
18360 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
18361 *
18362 * @example
18363 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
18364   <example module="bindExample">
18365     <file name="index.html">
18366       <script>
18367         angular.module('bindExample', [])
18368           .controller('ExampleController', ['$scope', function($scope) {
18369             $scope.name = 'Whirled';
18370           }]);
18371       </script>
18372       <div ng-controller="ExampleController">
18373         Enter name: <input type="text" ng-model="name"><br>
18374         Hello <span ng-bind="name"></span>!
18375       </div>
18376     </file>
18377     <file name="protractor.js" type="protractor">
18378       it('should check ng-bind', function() {
18379         var nameInput = element(by.model('name'));
18380
18381         expect(element(by.binding('name')).getText()).toBe('Whirled');
18382         nameInput.clear();
18383         nameInput.sendKeys('world');
18384         expect(element(by.binding('name')).getText()).toBe('world');
18385       });
18386     </file>
18387   </example>
18388 */
18389var ngBindDirective = ngDirective({
18390  compile: function(templateElement) {
18391    templateElement.addClass('ng-binding');
18392    return function (scope, element, attr) {
18393      element.data('$binding', attr.ngBind);
18394      scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
18395        // We are purposefully using == here rather than === because we want to
18396        // catch when value is "null or undefined"
18397        // jshint -W041
18398        element.text(value == undefined ? '' : value);
18399      });
18400    };
18401  }
18402});
18403
18404
18405/**
18406 * @ngdoc directive
18407 * @name ngBindTemplate
18408 *
18409 * @description
18410 * The `ngBindTemplate` directive specifies that the element
18411 * text content should be replaced with the interpolation of the template
18412 * in the `ngBindTemplate` attribute.
18413 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
18414 * expressions. This directive is needed since some HTML elements
18415 * (such as TITLE and OPTION) cannot contain SPAN elements.
18416 *
18417 * @element ANY
18418 * @param {string} ngBindTemplate template of form
18419 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
18420 *
18421 * @example
18422 * Try it here: enter text in text box and watch the greeting change.
18423   <example module="bindExample">
18424     <file name="index.html">
18425       <script>
18426         angular.module('bindExample', [])
18427           .controller('ExampleController', ['$scope', function ($scope) {
18428             $scope.salutation = 'Hello';
18429             $scope.name = 'World';
18430           }]);
18431       </script>
18432       <div ng-controller="ExampleController">
18433        Salutation: <input type="text" ng-model="salutation"><br>
18434        Name: <input type="text" ng-model="name"><br>
18435        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
18436       </div>
18437     </file>
18438     <file name="protractor.js" type="protractor">
18439       it('should check ng-bind', function() {
18440         var salutationElem = element(by.binding('salutation'));
18441         var salutationInput = element(by.model('salutation'));
18442         var nameInput = element(by.model('name'));
18443
18444         expect(salutationElem.getText()).toBe('Hello World!');
18445
18446         salutationInput.clear();
18447         salutationInput.sendKeys('Greetings');
18448         nameInput.clear();
18449         nameInput.sendKeys('user');
18450
18451         expect(salutationElem.getText()).toBe('Greetings user!');
18452       });
18453     </file>
18454   </example>
18455 */
18456var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
18457  return function(scope, element, attr) {
18458    // TODO: move this to scenario runner
18459    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
18460    element.addClass('ng-binding').data('$binding', interpolateFn);
18461    attr.$observe('ngBindTemplate', function(value) {
18462      element.text(value);
18463    });
18464  };
18465}];
18466
18467
18468/**
18469 * @ngdoc directive
18470 * @name ngBindHtml
18471 *
18472 * @description
18473 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
18474 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
18475 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
18476 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
18477 * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
18478 * include "angular-sanitize.js" in your application.
18479 *
18480 * You may also bypass sanitization for values you know are safe. To do so, bind to
18481 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
18482 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
18483 *
18484 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
18485 * will have an exception (instead of an exploit.)
18486 *
18487 * @element ANY
18488 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18489 *
18490 * @example
18491
18492   <example module="bindHtmlExample" deps="angular-sanitize.js">
18493     <file name="index.html">
18494       <div ng-controller="ExampleController">
18495        <p ng-bind-html="myHTML"></p>
18496       </div>
18497     </file>
18498
18499     <file name="script.js">
18500       angular.module('bindHtmlExample', ['ngSanitize'])
18501         .controller('ExampleController', ['$scope', function($scope) {
18502           $scope.myHTML =
18503              'I am an <code>HTML</code>string with ' +
18504              '<a href="#">links!</a> and other <em>stuff</em>';
18505         }]);
18506     </file>
18507
18508     <file name="protractor.js" type="protractor">
18509       it('should check ng-bind-html', function() {
18510         expect(element(by.binding('myHTML')).getText()).toBe(
18511             'I am an HTMLstring with links! and other stuff');
18512       });
18513     </file>
18514   </example>
18515 */
18516var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
18517  return {
18518    compile: function (tElement) {
18519      tElement.addClass('ng-binding');
18520
18521      return function (scope, element, attr) {
18522        element.data('$binding', attr.ngBindHtml);
18523
18524        var parsed = $parse(attr.ngBindHtml);
18525
18526        function getStringValue() {
18527          return (parsed(scope) || '').toString();
18528        }
18529
18530        scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
18531          element.html($sce.getTrustedHtml(parsed(scope)) || '');
18532        });
18533      };
18534    }
18535  };
18536}];
18537
18538function classDirective(name, selector) {
18539  name = 'ngClass' + name;
18540  return ['$animate', function($animate) {
18541    return {
18542      restrict: 'AC',
18543      link: function(scope, element, attr) {
18544        var oldVal;
18545
18546        scope.$watch(attr[name], ngClassWatchAction, true);
18547
18548        attr.$observe('class', function(value) {
18549          ngClassWatchAction(scope.$eval(attr[name]));
18550        });
18551
18552
18553        if (name !== 'ngClass') {
18554          scope.$watch('$index', function($index, old$index) {
18555            // jshint bitwise: false
18556            var mod = $index & 1;
18557            if (mod !== (old$index & 1)) {
18558              var classes = arrayClasses(scope.$eval(attr[name]));
18559              mod === selector ?
18560                addClasses(classes) :
18561                removeClasses(classes);
18562            }
18563          });
18564        }
18565
18566        function addClasses(classes) {
18567          var newClasses = digestClassCounts(classes, 1);
18568          attr.$addClass(newClasses);
18569        }
18570
18571        function removeClasses(classes) {
18572          var newClasses = digestClassCounts(classes, -1);
18573          attr.$removeClass(newClasses);
18574        }
18575
18576        function digestClassCounts (classes, count) {
18577          var classCounts = element.data('$classCounts') || {};
18578          var classesToUpdate = [];
18579          forEach(classes, function (className) {
18580            if (count > 0 || classCounts[className]) {
18581              classCounts[className] = (classCounts[className] || 0) + count;
18582              if (classCounts[className] === +(count > 0)) {
18583                classesToUpdate.push(className);
18584              }
18585            }
18586          });
18587          element.data('$classCounts', classCounts);
18588          return classesToUpdate.join(' ');
18589        }
18590
18591        function updateClasses (oldClasses, newClasses) {
18592          var toAdd = arrayDifference(newClasses, oldClasses);
18593          var toRemove = arrayDifference(oldClasses, newClasses);
18594          toRemove = digestClassCounts(toRemove, -1);
18595          toAdd = digestClassCounts(toAdd, 1);
18596
18597          if (toAdd.length === 0) {
18598            $animate.removeClass(element, toRemove);
18599          } else if (toRemove.length === 0) {
18600            $animate.addClass(element, toAdd);
18601          } else {
18602            $animate.setClass(element, toAdd, toRemove);
18603          }
18604        }
18605
18606        function ngClassWatchAction(newVal) {
18607          if (selector === true || scope.$index % 2 === selector) {
18608            var newClasses = arrayClasses(newVal || []);
18609            if (!oldVal) {
18610              addClasses(newClasses);
18611            } else if (!equals(newVal,oldVal)) {
18612              var oldClasses = arrayClasses(oldVal);
18613              updateClasses(oldClasses, newClasses);
18614            }
18615          }
18616          oldVal = shallowCopy(newVal);
18617        }
18618      }
18619    };
18620
18621    function arrayDifference(tokens1, tokens2) {
18622      var values = [];
18623
18624      outer:
18625      for(var i = 0; i < tokens1.length; i++) {
18626        var token = tokens1[i];
18627        for(var j = 0; j < tokens2.length; j++) {
18628          if(token == tokens2[j]) continue outer;
18629        }
18630        values.push(token);
18631      }
18632      return values;
18633    }
18634
18635    function arrayClasses (classVal) {
18636      if (isArray(classVal)) {
18637        return classVal;
18638      } else if (isString(classVal)) {
18639        return classVal.split(' ');
18640      } else if (isObject(classVal)) {
18641        var classes = [], i = 0;
18642        forEach(classVal, function(v, k) {
18643          if (v) {
18644            classes = classes.concat(k.split(' '));
18645          }
18646        });
18647        return classes;
18648      }
18649      return classVal;
18650    }
18651  }];
18652}
18653
18654/**
18655 * @ngdoc directive
18656 * @name ngClass
18657 * @restrict AC
18658 *
18659 * @description
18660 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18661 * an expression that represents all classes to be added.
18662 *
18663 * The directive operates in three different ways, depending on which of three types the expression
18664 * evaluates to:
18665 *
18666 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18667 * names.
18668 *
18669 * 2. If the expression evaluates to an array, each element of the array should be a string that is
18670 * one or more space-delimited class names.
18671 *
18672 * 3. If the expression evaluates to an object, then for each key-value pair of the
18673 * object with a truthy value the corresponding key is used as a class name.
18674 *
18675 * The directive won't add duplicate classes if a particular class was already set.
18676 *
18677 * When the expression changes, the previously added classes are removed and only then the
18678 * new classes are added.
18679 *
18680 * @animations
18681 * add - happens just before the class is applied to the element
18682 * remove - happens just before the class is removed from the element
18683 *
18684 * @element ANY
18685 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18686 *   of the evaluation can be a string representing space delimited class
18687 *   names, an array, or a map of class names to boolean values. In the case of a map, the
18688 *   names of the properties whose values are truthy will be added as css classes to the
18689 *   element.
18690 *
18691 * @example Example that demonstrates basic bindings via ngClass directive.
18692   <example>
18693     <file name="index.html">
18694       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18695       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18696       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18697       <input type="checkbox" ng-model="error"> error (apply "red" class)
18698       <hr>
18699       <p ng-class="style">Using String Syntax</p>
18700       <input type="text" ng-model="style" placeholder="Type: bold strike red">
18701       <hr>
18702       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18703       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18704       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18705       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18706     </file>
18707     <file name="style.css">
18708       .strike {
18709         text-decoration: line-through;
18710       }
18711       .bold {
18712           font-weight: bold;
18713       }
18714       .red {
18715           color: red;
18716       }
18717     </file>
18718     <file name="protractor.js" type="protractor">
18719       var ps = element.all(by.css('p'));
18720
18721       it('should let you toggle the class', function() {
18722
18723         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18724         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18725
18726         element(by.model('important')).click();
18727         expect(ps.first().getAttribute('class')).toMatch(/bold/);
18728
18729         element(by.model('error')).click();
18730         expect(ps.first().getAttribute('class')).toMatch(/red/);
18731       });
18732
18733       it('should let you toggle string example', function() {
18734         expect(ps.get(1).getAttribute('class')).toBe('');
18735         element(by.model('style')).clear();
18736         element(by.model('style')).sendKeys('red');
18737         expect(ps.get(1).getAttribute('class')).toBe('red');
18738       });
18739
18740       it('array example should have 3 classes', function() {
18741         expect(ps.last().getAttribute('class')).toBe('');
18742         element(by.model('style1')).sendKeys('bold');
18743         element(by.model('style2')).sendKeys('strike');
18744         element(by.model('style3')).sendKeys('red');
18745         expect(ps.last().getAttribute('class')).toBe('bold strike red');
18746       });
18747     </file>
18748   </example>
18749
18750   ## Animations
18751
18752   The example below demonstrates how to perform animations using ngClass.
18753
18754   <example module="ngAnimate" deps="angular-animate.js" animations="true">
18755     <file name="index.html">
18756      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18757      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18758      <br>
18759      <span class="base-class" ng-class="myVar">Sample Text</span>
18760     </file>
18761     <file name="style.css">
18762       .base-class {
18763         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18764         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18765       }
18766
18767       .base-class.my-class {
18768         color: red;
18769         font-size:3em;
18770       }
18771     </file>
18772     <file name="protractor.js" type="protractor">
18773       it('should check ng-class', function() {
18774         expect(element(by.css('.base-class')).getAttribute('class')).not.
18775           toMatch(/my-class/);
18776
18777         element(by.id('setbtn')).click();
18778
18779         expect(element(by.css('.base-class')).getAttribute('class')).
18780           toMatch(/my-class/);
18781
18782         element(by.id('clearbtn')).click();
18783
18784         expect(element(by.css('.base-class')).getAttribute('class')).not.
18785           toMatch(/my-class/);
18786       });
18787     </file>
18788   </example>
18789
18790
18791   ## ngClass and pre-existing CSS3 Transitions/Animations
18792   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18793   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18794   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18795   to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18796   {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18797 */
18798var ngClassDirective = classDirective('', true);
18799
18800/**
18801 * @ngdoc directive
18802 * @name ngClassOdd
18803 * @restrict AC
18804 *
18805 * @description
18806 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18807 * {@link ng.directive:ngClass ngClass}, except they work in
18808 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18809 *
18810 * This directive can be applied only within the scope of an
18811 * {@link ng.directive:ngRepeat ngRepeat}.
18812 *
18813 * @element ANY
18814 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18815 *   of the evaluation can be a string representing space delimited class names or an array.
18816 *
18817 * @example
18818   <example>
18819     <file name="index.html">
18820        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18821          <li ng-repeat="name in names">
18822           <span ng-class-odd="'odd'" ng-class-even="'even'">
18823             {{name}}
18824           </span>
18825          </li>
18826        </ol>
18827     </file>
18828     <file name="style.css">
18829       .odd {
18830         color: red;
18831       }
18832       .even {
18833         color: blue;
18834       }
18835     </file>
18836     <file name="protractor.js" type="protractor">
18837       it('should check ng-class-odd and ng-class-even', function() {
18838         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18839           toMatch(/odd/);
18840         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18841           toMatch(/even/);
18842       });
18843     </file>
18844   </example>
18845 */
18846var ngClassOddDirective = classDirective('Odd', 0);
18847
18848/**
18849 * @ngdoc directive
18850 * @name ngClassEven
18851 * @restrict AC
18852 *
18853 * @description
18854 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18855 * {@link ng.directive:ngClass ngClass}, except they work in
18856 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18857 *
18858 * This directive can be applied only within the scope of an
18859 * {@link ng.directive:ngRepeat ngRepeat}.
18860 *
18861 * @element ANY
18862 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18863 *   result of the evaluation can be a string representing space delimited class names or an array.
18864 *
18865 * @example
18866   <example>
18867     <file name="index.html">
18868        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18869          <li ng-repeat="name in names">
18870           <span ng-class-odd="'odd'" ng-class-even="'even'">
18871             {{name}} &nbsp; &nbsp; &nbsp;
18872           </span>
18873          </li>
18874        </ol>
18875     </file>
18876     <file name="style.css">
18877       .odd {
18878         color: red;
18879       }
18880       .even {
18881         color: blue;
18882       }
18883     </file>
18884     <file name="protractor.js" type="protractor">
18885       it('should check ng-class-odd and ng-class-even', function() {
18886         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18887           toMatch(/odd/);
18888         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18889           toMatch(/even/);
18890       });
18891     </file>
18892   </example>
18893 */
18894var ngClassEvenDirective = classDirective('Even', 1);
18895
18896/**
18897 * @ngdoc directive
18898 * @name ngCloak
18899 * @restrict AC
18900 *
18901 * @description
18902 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18903 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18904 * directive to avoid the undesirable flicker effect caused by the html template display.
18905 *
18906 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18907 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18908 * of the browser view.
18909 *
18910 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18911 * `angular.min.js`.
18912 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18913 *
18914 * ```css
18915 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18916 *   display: none !important;
18917 * }
18918 * ```
18919 *
18920 * When this css rule is loaded by the browser, all html elements (including their children) that
18921 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18922 * during the compilation of the template it deletes the `ngCloak` element attribute, making
18923 * the compiled element visible.
18924 *
18925 * For the best result, the `angular.js` script must be loaded in the head section of the html
18926 * document; alternatively, the css rule above must be included in the external stylesheet of the
18927 * application.
18928 *
18929 * Legacy browsers, like IE7, do not provide attribute selector support (a
18929dded in CSS 2.1) so they
18930 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18931 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18932 *
18933 * @element ANY
18934 *
18935 * @example
18936   <example>
18937     <file name="index.html">
18938        <div id="template1" ng-cloak>{{ 'hello' }}</div>
18939        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18940     </file>
18941     <file name="protractor.js" type="protractor">
18942       it('should remove the template directive and css class', function() {
18943         expect($('#template1').getAttribute('ng-cloak')).
18944           toBeNull();
18945         expect($('#template2').getAttribute('ng-cloak')).
18946           toBeNull();
18947       });
18948     </file>
18949   </example>
18950 *
18951 */
18952var ngCloakDirective = ngDirective({
18953  compile: function(element, attr) {
18954    attr.$set('ngCloak', undefined);
18955    element.removeClass('ng-cloak');
18956  }
18957});
18958
18959/**
18960 * @ngdoc directive
18961 * @name ngController
18962 *
18963 * @description
18964 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18965 * supports the principles behind the Model-View-Controller design pattern.
18966 *
18967 * MVC components in angular:
18968 *
18969 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
18970 *   are accessed through bindings.
18971 * * View — The template (HTML with data bindings) that is rendered into the View.
18972 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18973 *   logic behind the application to decorate the scope with functions and values
18974 *
18975 * Note that you can also attach controllers to the DOM by declaring it in a route definition
18976 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18977 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18978 * and executed twice.
18979 *
18980 * @element ANY
18981 * @scope
18982 * @priority 500
18983 * @param {expression} ngController Name of a globally accessible constructor function or an
18984 *     {@link guide/expression expression} that on the current scope evaluates to a
18985 *     constructor function. The controller instance can be published into a scope property
18986 *     by specifying `as propertyName`.
18987 *
18988 * @example
18989 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18990 * greeting are methods declared on the controller (see source tab). These methods can
18991 * easily be called from the angular markup. Any changes to the data are automatically reflected
18992 * in the View without the need for a manual update.
18993 *
18994 * Two different declaration styles are included below:
18995 *
18996 * * one binds methods and properties directly onto the controller using `this`:
18997 * `ng-controller="SettingsController1 as settings"`
18998 * * one injects `$scope` into the controller:
18999 * `ng-controller="SettingsController2"`
19000 *
19001 * The second option is more common in the Angular community, and is generally used in boilerplates
19002 * and in this guide. However, there are advantages to binding properties directly to the controller
19003 * and avoiding scope.
19004 *
19005 * * Using `controller as` makes it obvious which controller you are accessing in the template when
19006 * multiple controllers apply to an element.
19007 * * If you are writing your controllers as classes you have easier access to the properties and
19008 * methods, which will appear on the scope, from inside the controller code.
19009 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
19010 * inheritance masking primitives.
19011 *
19012 * This example demonstrates the `controller as` syntax.
19013 *
19014 * <example name="ngControllerAs" module="controllerAsExample">
19015 *   <file name="index.html">
19016 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
19017 *      Name: <input type="text" ng-model="settings.name"/>
19018 *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
19019 *      Contact:
19020 *      <ul>
19021 *        <li ng-repeat="contact in settings.contacts">
19022 *          <select ng-model="contact.type">
19023 *             <option>phone</option>
19024 *             <option>email</option>
19025 *          </select>
19026 *          <input type="text" ng-model="contact.value"/>
19027 *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
19028 *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
19029 *        </li>
19030 *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
19031 *     </ul>
19032 *    </div>
19033 *   </file>
19034 *   <file name="app.js">
19035 *    angular.module('controllerAsExample', [])
19036 *      .controller('SettingsController1', SettingsController1);
19037 *
19038 *    function SettingsController1() {
19039 *      this.name = "John Smith";
19040 *      this.contacts = [
19041 *        {type: 'phone', value: '408 555 1212'},
19042 *        {type: 'email', value: '[email protected]'} ];
19043 *    }
19044 *
19045 *    SettingsController1.prototype.greet = function() {
19046 *      alert(this.name);
19047 *    };
19048 *
19049 *    SettingsController1.prototype.addContact = function() {
19050 *      this.contacts.push({type: 'email', value: '[email protected]'});
19051 *    };
19052 *
19053 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
19054 *     var index = this.contacts.indexOf(contactToRemove);
19055 *      this.contacts.splice(index, 1);
19056 *    };
19057 *
19058 *    SettingsController1.prototype.clearContact = function(contact) {
19059 *      contact.type = 'phone';
19060 *      contact.value = '';
19061 *    };
19062 *   </file>
19063 *   <file name="protractor.js" type="protractor">
19064 *     it('should check controller as', function() {
19065 *       var container = element(by.id('ctrl-as-exmpl'));
19066 *         expect(container.element(by.model('settings.name'))
19067 *           .getAttribute('value')).toBe('John Smith');
19068 *
19069 *       var firstRepeat =
19070 *           container.element(by.repeater('contact in settings.contacts').row(0));
19071 *       var secondRepeat =
19072 *           container.element(by.repeater('contact in settings.contacts').row(1));
19073 *
19074 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
19075 *           .toBe('408 555 1212');
19076 *
19077 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
19078 *           .toBe('[email protected]');
19079 *
19080 *       firstRepeat.element(by.linkText('clear')).click();
19081 *
19082 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
19083 *           .toBe('');
19084 *
19085 *       container.element(by.linkText('add')).click();
19086 *
19087 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
19088 *           .element(by.model('contact.value'))
19089 *           .getAttribute('value'))
19090 *           .toBe('[email protected]');
19091 *     });
19092 *   </file>
19093 * </example>
19094 *
19095 * This example demonstrates the "attach to `$scope`" style of controller.
19096 *
19097 * <example name="ngController" module="controllerExample">
19098 *  <file name="index.html">
19099 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
19100 *     Name: <input type="text" ng-model="name"/>
19101 *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
19102 *     Contact:
19103 *     <ul>
19104 *       <li ng-repeat="contact in contacts">
19105 *         <select ng-model="contact.type">
19106 *            <option>phone</option>
19107 *            <option>email</option>
19108 *         </select>
19109 *         <input type="text" ng-model="contact.value"/>
19110 *         [ <a href="" ng-click="clearContact(contact)">clear</a>
19111 *         | <a href="" ng-click="removeContact(contact)">X</a> ]
19112 *       </li>
19113 *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
19114 *    </ul>
19115 *   </div>
19116 *  </file>
19117 *  <file name="app.js">
19118 *   angular.module('controllerExample', [])
19119 *     .controller('SettingsController2', ['$scope', SettingsController2]);
19120 *
19121 *   function SettingsController2($scope) {
19122 *     $scope.name = "John Smith";
19123 *     $scope.contacts = [
19124 *       {type:'phone', value:'408 555 1212'},
19125 *       {type:'email', value:'[email protected]'} ];
19126 *
19127 *     $scope.greet = function() {
19128 *       alert($scope.name);
19129 *     };
19130 *
19131 *     $scope.addContact = function() {
19132 *       $scope.contacts.push({type:'email', value:'[email protected]'});
19133 *     };
19134 *
19135 *     $scope.removeContact = function(contactToRemove) {
19136 *       var index = $scope.contacts.indexOf(contactToRemove);
19137 *       $scope.contacts.splice(index, 1);
19138 *     };
19139 *
19140 *     $scope.clearContact = function(contact) {
19141 *       contact.type = 'phone';
19142 *       contact.value = '';
19143 *     };
19144 *   }
19145 *  </file>
19146 *  <file name="protractor.js" type="protractor">
19147 *    it('should check controller', function() {
19148 *      var container = element(by.id('ctrl-exmpl'));
19149 *
19150 *      expect(container.element(by.model('name'))
19151 *          .getAttribute('value')).toBe('John Smith');
19152 *
19153 *      var firstRepeat =
19154 *          container.element(by.repeater('contact in contacts').row(0));
19155 *      var secondRepeat =
19156 *          container.element(by.repeater('contact in contacts').row(1));
19157 *
19158 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
19159 *          .toBe('408 555 1212');
19160 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
19161 *          .toBe('[email protected]');
19162 *
19163 *      firstRepeat.element(by.linkText('clear')).click();
19164 *
19165 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
19166 *          .toBe('');
19167 *
19168 *      container.element(by.linkText('add')).click();
19169 *
19170 *      expect(container.element(by.repeater('contact in contacts').row(2))
19171 *          .element(by.model('contact.value'))
19172 *          .getAttribute('value'))
19173 *          .toBe('[email protected]');
19174 *    });
19175 *  </file>
19176 *</example>
19177
19178 */
19179var ngControllerDirective = [function() {
19180  return {
19181    scope: true,
19182    controller: '@',
19183    priority: 500
19184  };
19185}];
19186
19187/**
19188 * @ngdoc directive
19189 * @name ngCsp
19190 *
19191 * @element html
19192 * @description
19193 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
19194 *
19195 * This is necessary when developing things like Google Chrome Extensions.
19196 *
19197 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
19198 * For Angular to be CSP compatible there are only two things that we need to do differently:
19199 *
19200 * - don't use `Function` constructor to generate optimized value getters
19201 * - don't inject custom stylesheet into the document
19202 *
19203 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
19204 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
19205 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
19206 * be raised.
19207 *
19208 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
19209 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
19210 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
19211 *
19212 * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
19213 * autodetection however triggers a CSP error to be logged in the console:
19214 *
19215 * ```
19216 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
19217 * script in the following Content Security Policy directive: "default-src 'self'". Note that
19218 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
19219 * ```
19220 *
19221 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
19222 * directive on the root element of the application or on the `angular.js` script tag, whichever
19223 * appears first in the html document.
19224 *
19225 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
19226 *
19227 * @example
19228 * This example shows how to apply the `ngCsp` directive to the `html` tag.
19229   ```html
19230     <!doctype html>
19231     <html ng-app ng-csp>
19232     ...
19233     ...
19234     </html>
19235   ```
19236 */
19237
19238// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
19239// bootstrap the system (before $parse is instantiated), for this reason we just have
19240// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
19241
19242/**
19243 * @ngdoc directive
19244 * @name ngClick
19245 *
19246 * @description
19247 * The ngClick directive allows you to specify custom behavior when
19248 * an element is clicked.
19249 *
19250 * @element ANY
19251 * @priority 0
19252 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
19253 * click. ({@link guide/expression#-event- Event object is available as `$event`})
19254 *
19255 * @example
19256   <example>
19257     <file name="index.html">
19258      <button ng-click="count = count + 1" ng-init="count=0">
19259        Increment
19260      </button>
19261      <span>
19262        count: {{count}}
19263      <span>
19264     </file>
19265     <file name="protractor.js" type="protractor">
19266       it('should check ng-click', function() {
19267         expect(element(by.binding('count')).getText()).toMatch('0');
19268         element(by.css('button')).click();
19269         expect(element(by.binding('count')).getText()).toMatch('1');
19270       });
19271     </file>
19272   </example>
19273 */
19274/*
19275 * A collection of directives that allows creation of custom event handlers that are defined as
19276 * angular expressions and are compiled and executed within the current scope.
19277 */
19278var ngEventDirectives = {};
19279
19280// For events that might fire synchronously during DOM manipulation
19281// we need to execute their event handlers asynchronously using $evalAsync,
19282// so that they are not executed in an inconsistent state.
19283var forceAsyncEvents = {
19284  'blur': true,
19285  'focus': true
19286};
19287forEach(
19288  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
19289  function(eventName) {
19290    var directiveName = directiveNormalize('ng-' + eventName);
19291    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
19292      return {
19293        compile: function($element, attr) {
19294          // We expose the powerful $event object on the scope that provides access to the Window,
19295          // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
19296          // checks at the cost of speed since event handler expressions are not executed as
19297          // frequently as regular change detection.
19298          var fn = $parse(attr[directiveName], /* expensiveChecks */ true);
19299          return function ngEventHandler(scope, element) {
19300            element.on(eventName, function(event) {
19301              var callback = function() {
19302                fn(scope, {$event:event});
19303              };
19304              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
19305                scope.$evalAsync(callback);
19306              } else {
19307                scope.$apply(callback);
19308              }
19309            });
19310          };
19311        }
19312      };
19313    }];
19314  }
19315);
19316
19317/**
19318 * @ngdoc directive
19319 * @name ngDblclick
19320 *
19321 * @description
19322 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
19323 *
19324 * @element ANY
19325 * @priority 0
19326 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
19327 * a dblclick. (The Event object is available as `$event`)
19328 *
19329 * @example
19330   <example>
19331     <file name="index.html">
19332      <button ng-dblclick="count = count + 1" ng-init="count=0">
19333        Increment (on double click)
19334      </button>
19335      count: {{count}}
19336     </file>
19337   </example>
19338 */
19339
19340
19341/**
19342 * @ngdoc directive
19343 * @name ngMousedown
19344 *
19345 * @description
19346 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
19347 *
19348 * @element ANY
19349 * @priority 0
19350 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
19351 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
19352 *
19353 * @example
19354   <example>
19355     <file name="index.html">
19356      <button ng-mousedown="count = count + 1" ng-init="count=0">
19357        Increment (on mouse down)
19358      </button>
19359      count: {{count}}
19360     </file>
19361   </example>
19362 */
19363
19364
19365/**
19366 * @ngdoc directive
19367 * @name ngMouseup
19368 *
19369 * @description
19370 * Specify custom behavior on mouseup event.
19371 *
19372 * @element ANY
19373 * @priority 0
19374 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
19375 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
19376 *
19377 * @example
19378   <example>
19379     <file name="index.html">
19380      <button ng-mouseup="count = count + 1" ng-init="count=0">
19381        Increment (on mouse up)
19382      </button>
19383      count: {{count}}
19384     </file>
19385   </example>
19386 */
19387
19388/**
19389 * @ngdoc directive
19390 * @name ngMouseover
19391 *
19392 * @description
19393 * Specify custom behavior on mouseover event.
19394 *
19395 * @element ANY
19396 * @priority 0
19397 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
19398 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
19399 *
19400 * @example
19401   <example>
19402     <file name="index.html">
19403      <button ng-mouseover="count = count + 1" ng-init="count=0">
19404        Increment (when mouse is over)
19405      </button>
19406      count: {{count}}
19407     </file>
19408   </example>
19409 */
19410
19411
19412/**
19413 * @ngdoc directive
19414 * @name ngMouseenter
19415 *
19416 * @description
19417 * Specify custom behavior on mouseenter event.
19418 *
19419 * @element ANY
19420 * @priority 0
19421 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
19422 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
19423 *
19424 * @example
19425   <example>
19426     <file name="index.html">
19427      <button ng-mouseenter="count = count + 1" ng-init="count=0">
19428        Increment (when mouse enters)
19429      </button>
19430      count: {{count}}
19431     </file>
19432   </example>
19433 */
19434
19435
19436/**
19437 * @ngdoc directive
19438 * @name ngMouseleave
19439 *
19440 * @description
19441 * Specify custom behavior on mouseleave event.
19442 *
19443 * @element ANY
19444 * @priority 0
19445 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
19446 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
19447 *
19448 * @example
19449   <example>
19450     <file name="index.html">
19451      <button ng-mouseleave="count = count + 1" ng-init="count=0">
19452        Increment (when mouse leaves)
19453      </button>
19454      count: {{count}}
19455     </file>
19456   </example>
19457 */
19458
19459
19460/**
19461 * @ngdoc directive
19462 * @name ngMousemove
19463 *
19464 * @description
19465 * Specify custom behavior on mousemove event.
19466 *
19467 * @element ANY
19468 * @priority 0
19469 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
19470 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
19471 *
19472 * @example
19473   <example>
19474     <file name="index.html">
19475      <button ng-mousemove="count = count + 1" ng-init="count=0">
19476        Increment (when mouse moves)
19477      </button>
19478      count: {{count}}
19479     </file>
19480   </example>
19481 */
19482
19483
19484/**
19485 * @ngdoc directive
19486 * @name ngKeydown
19487 *
19488 * @description
19489 * Specify custom behavior on keydown event.
19490 *
19491 * @element ANY
19492 * @priority 0
19493 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
19494 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19495 *
19496 * @example
19497   <example>
19498     <file name="index.html">
19499      <input ng-keydown="count = count + 1" ng-init="count=0">
19500      key down count: {{count}}
19501     </file>
19502   </example>
19503 */
19504
19505
19506/**
19507 * @ngdoc directive
19508 * @name ngKeyup
19509 *
19510 * @description
19511 * Specify custom behavior on keyup event.
19512 *
19513 * @element ANY
19514 * @priority 0
19515 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
19516 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
19517 *
19518 * @example
19519   <example>
19520     <file name="index.html">
19521       <p>Typing in the input box below updates the key count</p>
19522       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
19523
19524       <p>Typing in the input box below updates the keycode</p>
19525       <input ng-keyup="event=$event">
19526       <p>event keyCode: {{ event.keyCode }}</p>
19527       <p>event altKey: {{ event.altKey }}</p>
19528     </file>
19529   </example>
19530 */
19531
19532
19533/**
19534 * @ngdoc directive
19535 * @name ngKeypress
19536 *
19537 * @description
19538 * Specify custom behavior on keypress event.
19539 *
19540 * @element ANY
19541 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
19542 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
19543 * and can be interrogated for keyCode, altKey, etc.)
19544 *
19545 * @example
19546   <example>
19547     <file name="index.html">
19548      <input ng-keypress="count = count + 1" ng-init="count=0">
19549      key press count: {{count}}
19550     </file>
19551   </example>
19552 */
19553
19554
19555/**
19556 * @ngdoc directive
19557 * @name ngSubmit
19558 *
19559 * @description
19560 * Enables binding angular expressions to onsubmit events.
19561 *
19562 * Additionally it prevents the default action (which for form means 
19562sending the request to the
19563 * server and reloading the current page), but only if the form does not contain `action`,
19564 * `data-action`, or `x-action` attributes.
19565 *
19566 * <div class="alert alert-warning">
19567 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
19568 * `ngSubmit` handlers together. See the
19569 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
19570 * for a detailed discussion of when `ngSubmit` may be triggered.
19571 * </div>
19572 *
19573 * @element form
19574 * @priority 0
19575 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
19576 * ({@link guide/expression#-event- Event object is available as `$event`})
19577 *
19578 * @example
19579   <example module="submitExample">
19580     <file name="index.html">
19581      <script>
19582        angular.module('submitExample', [])
19583          .controller('ExampleController', ['$scope', function($scope) {
19584            $scope.list = [];
19585            $scope.text = 'hello';
19586            $scope.submit = function() {
19587              if ($scope.text) {
19588                $scope.list.push(this.text);
19589                $scope.text = '';
19590              }
19591            };
19592          }]);
19593      </script>
19594      <form ng-submit="submit()" ng-controller="ExampleController">
19595        Enter text and hit enter:
19596        <input type="text" ng-model="text" name="text" />
19597        <input type="submit" id="submit" value="Submit" />
19598        <pre>list={{list}}</pre>
19599      </form>
19600     </file>
19601     <file name="protractor.js" type="protractor">
19602       it('should check ng-submit', function() {
19603         expect(element(by.binding('list')).getText()).toBe('list=[]');
19604         element(by.css('#submit')).click();
19605         expect(element(by.binding('list')).getText()).toContain('hello');
19606         expect(element(by.model('text')).getAttribute('value')).toBe('');
19607       });
19608       it('should ignore empty strings', function() {
19609         expect(element(by.binding('list')).getText()).toBe('list=[]');
19610         element(by.css('#submit')).click();
19611         element(by.css('#submit')).click();
19612         expect(element(by.binding('list')).getText()).toContain('hello');
19613        });
19614     </file>
19615   </example>
19616 */
19617
19618/**
19619 * @ngdoc directive
19620 * @name ngFocus
19621 *
19622 * @description
19623 * Specify custom behavior on focus event.
19624 *
19625 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
19626 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19627 * during an `$apply` to ensure a consistent state.
19628 *
19629 * @element window, input, select, textarea, a
19630 * @priority 0
19631 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
19632 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
19633 *
19634 * @example
19635 * See {@link ng.directive:ngClick ngClick}
19636 */
19637
19638/**
19639 * @ngdoc directive
19640 * @name ngBlur
19641 *
19642 * @description
19643 * Specify custom behavior on blur event.
19644 *
19645 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
19646 * an element has lost focus.
19647 *
19648 * Note: As the `blur` event is executed synchronously also during DOM manipulations
19649 * (e.g. removing a focussed input),
19650 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19651 * during an `$apply` to ensure a consistent state.
19652 *
19653 * @element window, input, select, textarea, a
19654 * @priority 0
19655 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
19656 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
19657 *
19658 * @example
19659 * See {@link ng.directive:ngClick ngClick}
19660 */
19661
19662/**
19663 * @ngdoc directive
19664 * @name ngCopy
19665 *
19666 * @description
19667 * Specify custom behavior on copy event.
19668 *
19669 * @element window, input, select, textarea, a
19670 * @priority 0
19671 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
19672 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
19673 *
19674 * @example
19675   <example>
19676     <file name="index.html">
19677      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
19678      copied: {{copied}}
19679     </file>
19680   </example>
19681 */
19682
19683/**
19684 * @ngdoc directive
19685 * @name ngCut
19686 *
19687 * @description
19688 * Specify custom behavior on cut event.
19689 *
19690 * @element window, input, select, textarea, a
19691 * @priority 0
19692 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
19693 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
19694 *
19695 * @example
19696   <example>
19697     <file name="index.html">
19698      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
19699      cut: {{cut}}
19700     </file>
19701   </example>
19702 */
19703
19704/**
19705 * @ngdoc directive
19706 * @name ngPaste
19707 *
19708 * @description
19709 * Specify custom behavior on paste event.
19710 *
19711 * @element window, input, select, textarea, a
19712 * @priority 0
19713 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19714 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19715 *
19716 * @example
19717   <example>
19718     <file name="index.html">
19719      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19720      pasted: {{paste}}
19721     </file>
19722   </example>
19723 */
19724
19725/**
19726 * @ngdoc directive
19727 * @name ngIf
19728 * @restrict A
19729 *
19730 * @description
19731 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19732 * {expression}. If the expression assigned to `ngIf` evaluates to a false
19733 * value then the element is removed from the DOM, otherwise a clone of the
19734 * element is reinserted into the DOM.
19735 *
19736 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19737 * element in the DOM rather than changing its visibility via the `display` css property.  A common
19738 * case when this difference is significant is when using css selectors that rely on an element's
19739 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
19739s.
19740 *
19741 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19742 * is created when the element is restored.  The scope created within `ngIf` inherits from
19743 * its parent scope using
19744 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
19745 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19746 * a javascript primitive defined in the parent scope. In this case any modifications made to the
19747 * variable within the child scope will override (hide) the value in the parent scope.
19748 *
19749 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19750 * is if an element's class attribute is directly modified after it's compiled, using something like
19751 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19752 * the added class will be lost because the original compiled state is used to regenerate the element.
19753 *
19754 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19755 * and `leave` effects.
19756 *
19757 * @animations
19758 * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
19759 * leave - happens just before the `ngIf` contents are removed from the DOM
19760 *
19761 * @element ANY
19762 * @scope
19763 * @priority 600
19764 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19765 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19766 *     element is added to the DOM tree.
19767 *
19768 * @example
19769  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19770    <file name="index.html">
19771      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19772      Show when checked:
19773      <span ng-if="checked" class="animate-if">
19774        I'm removed when the checkbox is unchecked.
19775      </span>
19776    </file>
19777    <file name="animations.css">
19778      .animate-if {
19779        background:white;
19780        border:1px solid black;
19781        padding:10px;
19782      }
19783
19784      .animate-if.ng-enter, .animate-if.ng-leave {
19785        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19786        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19787      }
19788
19789      .animate-if.ng-enter,
19790      .animate-if.ng-leave.ng-leave-active {
19791        opacity:0;
19792      }
19793
19794      .animate-if.ng-leave,
19795      .animate-if.ng-enter.ng-enter-active {
19796        opacity:1;
19797      }
19798    </file>
19799  </example>
19800 */
19801var ngIfDirective = ['$animate', function($animate) {
19802  return {
19803    transclude: 'element',
19804    priority: 600,
19805    terminal: true,
19806    restrict: 'A',
19807    $$tlb: true,
19808    link: function ($scope, $element, $attr, ctrl, $transclude) {
19809        var block, childScope, previousElements;
19810        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19811
19812          if (toBoolean(value)) {
19813            if (!childScope) {
19814              childScope = $scope.$new();
19815              $transclude(childScope, function (clone) {
19816                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19817                // Note: We only need the first/last node of the cloned nodes.
19818                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19819                // by a directive with templateUrl when its template arrives.
19820                block = {
19821                  clone: clone
19822                };
19823                $animate.enter(clone, $element.parent(), $element);
19824              });
19825            }
19826          } else {
19827            if(previousElements) {
19828              previousElements.remove();
19829              previousElements = null;
19830            }
19831            if(childScope) {
19832              childScope.$destroy();
19833              childScope = null;
19834            }
19835            if(block) {
19836              previousElements = getBlockElements(block.clone);
19837              $animate.leave(previousElements, function() {
19838                previousElements = null;
19839              });
19840              block = null;
19841            }
19842          }
19843        });
19844    }
19845  };
19846}];
19847
19848/**
19849 * @ngdoc directive
19850 * @name ngInclude
19851 * @restrict ECA
19852 *
19853 * @description
19854 * Fetches, compiles and includes an external HTML fragment.
19855 *
19856 * By default, the template URL is restricted to the same domain and protocol as the
19857 * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19858 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19859 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19860 * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19861 * ng.$sce Strict Contextual Escaping}.
19862 *
19863 * In addition, the browser's
19864 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19865 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19866 * policy may further restrict whether the template is successfully loaded.
19867 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19868 * access on some browsers.
19869 *
19870 * @animations
19871 * enter - animation is used to bring new content into the browser.
19872 * leave - animation is used to animate existing content away.
19873 *
19874 * The enter and leave animation occur concurrently.
19875 *
19876 * @scope
19877 * @priority 400
19878 *
19879 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19880 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19881 * @param {string=} onload Expression to evaluate when a new partial is loaded.
19882 *
19883 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19884 *                  $anchorScroll} to scroll the viewport after the content is loaded.
19885 *
19886 *                  - If the attribute is not set, disable scrolling.
19887 *                  - If the attribute is set without value, enable scrolling.
19888 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19889 *
19890 * @example
19891  <example module="includeExample" deps="angular-animate.js" animations="true">
19892    <file name="index.html">
19893     <div ng-controller="ExampleController">
19894       <select ng-model="template" ng-options="t.name for t in templates">
19895        <option value="">(blank)</option>
19896       </select>
19897       url of the template: <code>{{template.url}}</code>
19898       <hr/>
19899       <div class="slide-animate-container">
19900         <div class="slide-animate" ng-include="template.url"></div>
19901       </div>
19902     </div>
19903    </file>
19904    <file name="script.js">
19905      angular.module('includeExample', ['ngAnimate'])
19906        .controller('ExampleController', ['$scope', function($scope) {
19907          $scope.templates =
19908            [ { name: 'template1.html', url: 'template1.html'},
19909              { name: 'template2.html', url: 'template2.html'} ];
19910          $scope.template = $scope.templates[0];
19911        }]);
19912     </file>
19913    <file name="template1.html">
19914      Content of template1.html
19915    </file>
19916    <file name="template2.html">
19917      Content of template2.html
19918    </file>
19919    <file name="animations.css">
19920      .slide-animate-container {
19921        position:relative;
19922        background:white;
19923        border:1px solid black;
19924        height:40px;
19925        overflow:hidden;
19926      }
19927
19928      .slide-animate {
19929        padding:10px;
19930      }
19931
19932      .slide-animate.ng-enter, .slide-animate.ng-leave {
19933        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19934        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19935
19936        position:absolute;
19937        top:0;
19938        left:0;
19939        right:0;
19940        bottom:0;
19941        display:block;
19942        padding:10px;
19943      }
19944
19945      .slide-animate.ng-enter {
19946        top:-50px;
19947      }
19948      .slide-animate.ng-enter.ng-enter-active {
19949        top:0;
19950      }
19951
19952      .slide-animate.ng-leave {
19953        top:0;
19954      }
19955      .slide-animate.ng-leave.ng-leave-active {
19956        top:50px;
19957      }
19958    </file>
19959    <file name="protractor.js" type="protractor">
19960      var templateSelect = element(by.model('template'));
19961      var includeElem = element(by.css('[ng-include]'));
19962
19963      it('should load template1.html', function() {
19964        expect(includeElem.getText()).toMatch(/Content of template1.html/);
19965      });
19966
19967      it('should load template2.html', function() {
19968        if (browser.params.browser == 'firefox') {
19969          // Firefox can't handle using selects
19970          // See https://github.com/angular/protractor/issues/480
19971          return;
19972        }
19973        templateSelect.click();
19974        templateSelect.all(by.css('option')).get(2).click();
19975        expect(includeElem.getText()).toMatch(/Content of template2.html/);
19976      });
19977
19978      it('should change to blank', function() {
19979        if (browser.params.browser == 'firefox') {
19980          // Firefox can't handle using selects
19981          return;
19982        }
19983        templateSelect.click();
19984        templateSelect.all(by.css('option')).get(0).click();
19985        expect(includeElem.isPresent()).toBe(false);
19986      });
19987    </file>
19988  </example>
19989 */
19990
19991
19992/**
19993 * @ngdoc event
19994 * @name ngInclude#$includeContentRequested
19995 * @eventType emit on the scope ngInclude was declared in
19996 * @description
19997 * Emitted every time the ngInclude content is requested.
19998 */
19999
20000
20001/**
20002 * @ngdoc event
20003 * @name ngInclude#$includeContentLoaded
20004 * @eventType emit on the current ngInclude scope
20005 * @description
20006 * Emitted every time the ngInclude content is reloaded.
20007 */
20008var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
20009                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
20010  return {
20011    restrict: 'ECA',
20012    priority: 400,
20013    terminal: true,
20014    transclude: 'element',
20015    controller: angular.noop,
20016    compile: function(element, attr) {
20017      var srcExp = attr.ngInclude || attr.src,
20018          onloadExp = attr.onload || '',
20019          autoScrollExp = attr.autoscroll;
20020
20021      return function(scope, $element, $attr, ctrl, $transclude) {
20022        var changeCounter = 0,
20023            currentScope,
20024            previousElement,
20025            currentElement;
20026
20027        var cleanupLastIncludeContent = function() {
20028          if(previousElement) {
20029            previousElement.remove();
20030            previousElement = null;
20031          }
20032          if(currentScope) {
20033            currentScope.$destroy();
20034            currentScope = null;
20035          }
20036          if(currentElement) {
20037            $animate.leave(currentElement, function() {
20038              previousElement = null;
20039            });
20040            previousElement = currentElement;
20041            currentElement = null;
20042          }
20043        };
20044
20045        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
20046          var afterAnimation = function() {
20047            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
20048              $anchorScroll();
20049            }
20050          };
20051          var thisChangeId = ++changeCounter;
20052
20053          if (src) {
20054            $http.get(src, {cache: $templateCache}).success(function(response) {
20055              if (thisChangeId !== changeCounter) return;
20056              var newScope = scope.$new();
20057              ctrl.template = response;
20058
20059              // Note: This will also link all children of ng-include that were contained in the original
20060              // html. If that content contains controllers, ... they could pollute/change the scope.
20061              // However, using ng-include on an element with additional content does not make sense...
20062              // Note: We can't remove them in the cloneAttchFn of $transclude as that
20063              // function is called before linking the content, which would apply child
20064              // directives to non existing elements.
20065              var clone = $transclude(newScope, function(clone) {
20066                cleanupLastIncludeContent();
20067                $animate.enter(clone, null, $element, afterAnimation);
20068              });
20069
20070              currentScope = newScope;
20071              currentElement = clone;
20072
20073              currentScope.$emit('$includeContentLoaded');
20074              scope.$eval(onloadExp);
20075            }).error(function() {
20076              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
20077            });
20078            scope.$emit('$includeContentRequested');
20079          } else {
20080            cleanupLastIncludeContent();
20081            ctrl.template = null;
20082          }
20083        });
20084      };
20085    }
20086  };
20087}];
20088
20089// This directive is called during the $transclude call of the first `ngInclude` directive.
20090// It will replace and compile the content of the element with the loaded template.
20091// We need this directive so that the element content is already filled when
20092// the link function of another directive on the same element as ngInclude
20093// is called.
20094var ngIncludeFillContentDirective = ['$compile',
20095  function($compile) {
20096    return {
20097      restrict: 'ECA',
20098      priority: -400,
20099      require: 'ngInclude',
20100      link: function(scope, $element, $attr, ctrl) {
20101        $element.html(ctrl.template);
20102        $compile($element.contents())(scope);
20103      }
20104    };
20105  }];
20106
20107/**
20108 * @ngdoc directive
20109 * @name ngInit
20110 * @restrict AC
20111 *
20112 * @description
20113 * The `ngInit` directive allows you to evaluate an expression in the
20114 * current scope.
20115 *
20116 * <div class="alert alert-error">
20117 * The only appropriate use of `ngInit` is for aliasing special properties of
20118 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
20119 * should use {@link guide/controller controllers} rather than `ngInit`
20120 * to initialize values on a scope.
20121 * </div>
20122 * <div class="alert alert-warning">
20123 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
20124 * sure you have parenthesis for correct precedence:
20125 * <pre class="prettyprint">
20126 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
20127 * </pre>
20128 * </div>
20129 *
20130 * @priority 450
20131 *
20132 * @element ANY
20133 * @param {expression} ngInit {@link guide/expression Expression} to eval.
20134 *
20135 * @example
20136   <example module="initExample">
20137     <file name="index.html">
20138   <script>
20139     angular.module('initExample', [])
20140       .controller('ExampleController', ['$scope', function($scope) {
20141         $scope.list = [['a', 'b'], ['c', 'd']];
20142       }]);
20143   </script>
20144   <div ng-controller="ExampleController">
20145     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
20146       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
20147          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
20148       </div>
20149     </div>
20150   </div>
20151     </file>
20152     <file name="protractor.js" type="protractor">
20153       it('should alias index positions', function() {
20154         var elements = element.all(by.css('.example-init'));
20155         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
20156         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
20157         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
20158         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
20159       });
20160     </file>
20161   </example>
20162 */
20163var ngInitDirective = ngDirective({
20164  priority: 450,
20165  compile: function() {
20166    return {
20167      pre: function(scope, element, attrs) {
20168        scope.$eval(attrs.ngInit);
20169      }
20170    };
20171  }
20172});
20173
20174/**
20175 * @ngdoc directive
20176 * @name ngNonBindable
20177 * @restrict AC
20178 * @priority 1000
20179 *
20180 * @description
20181 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
20182 * DOM element. This is useful if the element contains what appears to be Angular directives and
20183 * bindings but which should be ignored by Angular. This could be the case if you have a site that
20184 * displays snippets of code, for instance.
20185 *
20186 * @element ANY
20187 *
20188 * @example
20189 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
20190 * but the one wrapped in `ngNonBindable` is left alone.
20191 *
20192 * @example
20193    <example>
20194      <file name="index.html">
20195        <div>Normal: {{1 + 2}}</div>
20196        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
20197      </file>
20198      <file name="protractor.js" type="protractor">
20199       it('should check ng-non-bindable', function() {
20200         expect(element(by.binding('1 + 2')).getText()).toContain('3');
20201         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
20202       });
20203      </file>
20204    </example>
20205 */
20206var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
20207
20208/**
20209 * @ngdoc directive
20210 * @name ngPluralize
20211 * @restrict EA
20212 *
20213 * @description
20214 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
20215 * These rules are bundled with angular.js, but can be overridden
20216 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
20217 * by specifying the mappings between
20218 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
20219 * and the strings to be displayed.
20220 *
20221 * # Plural categories and explicit number rules
20222 * There are two
20223 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
20224 * in Angular's default en-US locale: "one" and "other".
20225 *
20226 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
20227 * any number that is not 1), an explicit number rule can only match one number. For example, the
20228 * explicit number rule for "3" matches the number 3. There are examples of plural categories
20229 * and explicit number rules throughout the rest of this documentation.
20230 *
20231 * # Configuring ngPluralize
20232 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
20233 * You can also provide an optional attribute, `offset`.
20234 *
20235 * The value of the `count` attribute can be either a string or an {@link guide/expression
20236 * Angular expression}; these are evaluated on the current scope for its bound value.
20237 *
20238 * The `when` attribute specifies the mappings between plural categories and the actual
20239 * string to be displayed. The value of the attribute should be a JSON object.
20240 *
20241 * The following example shows how to configure ngPluralize:
20242 *
20243 * ```html
20244 * <ng-pluralize count="personCount"
20245                 when="{'0': 'Nobody is viewing.',
20246 *                      'one': '1 person is viewing.',
20247 *                      'other': '{} people are viewing.'}">
20248 * </ng-pluralize>
20249 *```
20250 *
20251 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
20252 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
20253 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
20254 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
20255 * show "a dozen people are viewing".
20256 *
20257 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
20258 * into pluralized strings. In the previous example, Angular will replace `{}` with
20259 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
20260 * for <span ng-non-bindable>{{numberExpression}}</span>.
20261 *
20262 * # Configuring ngPluralize with offset
20263 * The `offset` attribute allows further customization of pluralized text, which can result in
20264 * a better user experience. For example, instead of the message "4 people are viewing this document",
20265 * you might display "John, Kate and 2 others are viewing this document".
20266 * The offset attribute allows you to offset a number by any desired value.
20267 * Let's take a look at an example:
20268 *
20269 * ```html
20270 * <ng-pluralize count="personCount" offset=2
20271 *               when="{'0': 'Nobody is viewing.',
20272 *                      '1': '{{person1}} is viewing.',
20273 *                      '2': '{{person1}} and {{person2}} are viewing.',
20274 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
20275 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20276 * </ng-pluralize>
20277 * ```
20278 *
20279 * Notice that we are still using two plural categories(one, other), but we added
20280 * three explicit number rules 0, 1 and 2.
20281 * When one person, perhaps John, views the document, "John is viewing" will be shown.
20282 * When three people view the document, no explicit number rule is found, so
20283 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
20284 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
20285 * is shown.
20286 *
20287 * Note that when you specify offsets, you must provide explicit number rules for
20288 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
20289 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
20290 * plural categories "one" and "other".
20291 *
20292 * @param {string|expression} count The variable to be bound to.
20293 * @param {string} when The mapping between plural category to its corresponding strings.
20294 * @param {number=} offset Offset to deduct from the total number.
20295 *
20296 * @example
20297    <example module="pluralizeExample">
20298      <file name="index.html">
20299        <script>
20300          angular.module('pluralizeExample', [])
20301            .controller('ExampleController', ['$scope', function($scope) {
20302              $scope.person1 = 'Igor';
20303              $scope.person2 = 'Misko';
20304              $scope.personCount = 1;
20305            }]);
20306        </script>
20307        <div ng-controller="ExampleController">
20308          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
20309          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
20310          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
20311
20312          <!--- Example with simple pluralization rules for en locale --->
20313          Without Offset:
20314          <ng-pluralize count="personCount"
20315                        when="{'0': 'Nobody is viewing.',
20316                               'one': '1 person is viewing.',
20317                               'other': '{} people are viewing.'}">
20318          </ng-pluralize><br>
20319
20320          <!--- Example with offset --->
20321          With Offset(2):
20322          <ng-pluralize count="personCount" offset=2
20323                        when="{'0': 'Nobody is viewing.',
20324                               '1': '{{person1}} is viewing.',
20325                               '2': '{{person1}} and {{person2}} are viewing.',
20326                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
20327                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
20328          </ng-pluralize>
20329        </div>
20330      </file>
20331      <file name="protractor.js" type="protractor">
20332        it('should show correct pluralized string', function() {
20333          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
20334          var withOffset = element.all(by.css('ng-pluralize')).get(1);
20335          var countInput = element(by.model('personCount'));
20336
20337          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
20338          expect(withOffset.getText()).toEqual('Igor is viewing.');
20339
20340          countInput.clear();
20341          countInput.sendKeys('0');
20342
20343          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
20344          expect(withOffset.getText()).toEqual('Nobody is viewing.');
20345
20346          countInput.clear();
20347          countInput.sendKeys('2');
20348
20349          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
20350          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
20351
20352          countInput.clear();
20353          countInput.sendKeys('3');
20354
20355          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
20356          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
20357
20358          countInput.clear();
20359          countInput.sendKeys('4');
20360
20361          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
20362          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
20363        });
20364        it('should show data-bound names', function() {
20365          var withOffset = element.all(by.css('ng-pluralize')).get(1);
20366          var personCount = element(by.model('personCount'));
20367          var person1 = element(by.model('person1'));
20368          var person2 = element(by.model('person2'));
20369          personCount.clear();
20370          personCount.sendKeys('4');
20371          person1.clear();
20372          person1.sendKeys('Di');
20373          person2.clear();
20374          person2.sendKeys('Vojta');
20375          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
20376        });
20377      </file>
20378    </example>
20379 */
20380var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
20381  var BRACE = /{}/g;
20382  return {
20383    restrict: 'EA',
20384    link: function(scope, element, attr) {
20385      var numberExp = attr.count,
20386          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
20387          offset = attr.offset || 0,
20388          whens = scope.$eval(whenExp) || {},
20389          whensExpFns = {},
20390          startSymbol = $interpolate.startSymbol(),
20391          endSymbol = $interpolate.endSymbol(),
20392          isWhen = /^when(Minus)?(.+)$/;
20393
20394      forEach(attr, function(expression, attributeName) {
20395        if (isWhen.test(attributeName)) {
20396          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
20397            element.attr(attr.$attr[attributeName]);
20398        }
20399      });
20400      forEach(whens, function(expression, key) {
20401        whensExpFns[key] =
20402          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
20403            offset + endSymbol));
20404      });
20405
20406      scope.$watch(function ngPluralizeWatch() {
20407        var value = parseFloat(scope.$eval(numberExp));
20408
20409        if (!isNaN(value)) {
20410          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
20411          //check it against pluralization rules in $locale service
20412          if (!(value in whens)) value = $locale.pluralCat(value - offset);
20413           return whensExpFns[value](scope, element, true);
20414        } else {
20415          return '';
20416        }
20417      }, function ngPluralizeWatchAction(newVal) {
20418        element.text(newVal);
20419      });
20420    }
20421  };
20422}];
20423
20424/**
20425 * @ngdoc directive
20426 * @name ngRepeat
20427 *
20428 * @description
20429 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
20430 * instance gets its own scope, where the given loop variable is set to the current collection item,
20431 * and `$index` is set to the item index or key.
20432 *
20433 * Special properties are exposed on the local scope of each template instance, including:
20434 *
20435 * | Variable  | Type            | Details                                                                     |
20436 * |-----------|-----------------|-----------------------------------------------------------------------------|
20437 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
20438 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
20439 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
20440 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
20441 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
20442 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
20443 *
20444 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
20445 * This may be useful when, for instance, nesting ngRepeats.
20446 *
20447 * # Special repeat start and end points
20448 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
20449 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
20450 * 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)
20451 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
20452 *
20453 * The example below makes use of this feature:
20454 * ```html
20455 *   <header ng-repeat-start="item in items">
20456 *     Header {{ item }}
20457 *   </header>
20458 *   <div class="body">
20459 *     Body {{ item }}
20460 *   </div>
20461 *   <footer ng-repeat-end>
20462 *     Footer {{ item }}
20463 *   </footer>
20464 * ```
20465 *
20466 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
20467 * ```html
20468 *   <header>
20469 *     Header A
20470 *   </header>
20471 *   <div class="body">
20472 *     Body A
20473 *   </div>
20474 *   <footer>
20475 *     Footer A
20476 *   </footer>
20477 *   <header>
20478 *     Header B
20479 *   </header>
20480 *   <div class="body">
20481 *     Body B
20482 *   </div>
20483 *   <footer>
20484 *     Footer B
20485 *   </footer>
20486 * ```
20487 *
20488 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
20489 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
20490 *
20491 * @animations
20492 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
20493 *
20494 * **.leave** - when an item is removed from the list or when an item is filtered out
20495 *
20496 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
20497 *
20498 * @element ANY
20499 * @scope
20500 * @priority 1000
20501 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
20502 *   formats are currently supported:
20503 *
20504 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
20505 *     is a scope expression giving the collection to enumerate.
20506 *
20507 *     For example: `album in artist.albums`.
20508 *
20509 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
20510 *     and `expression` is the scope expression giving the collection to enumerate.
20511 *
20512 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
20513 *
20514 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
20515 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
20516 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
20517 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
20518 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
20519 *     before specifying a tracking expression.
20520 *
20521 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
20522 *     will be associated by item identity in the array.
20523 *
20524 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
20525 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
20526 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
20527 *     element in the same way in the DOM.
20528 *
20529 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
20530 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
20531 *     property is same.
20532 *
20533 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
20534 *     to items in conjunction with a tracking expression.
20535 *
20536 * @example
20537 * This example initializes the scope to a list of names and
20538 * then uses `ngRepeat` to display every person:
20539  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20540    <file name="index.html">
20541      <div ng-init="friends = [
20542        {name:'John', age:25, gender:'boy'},
20543        {name:'Jessie', age:30, gender:'girl'},
20544        {name:'Johanna', age:28, gender:'girl'},
20545        {name:'Joy', age:15, gender:'girl'},
20546        {name:'Mary', age:28, gender:'girl'},
20547        {name:'Peter', age:95, gender:'boy'},
20548        {name:'Sebastian', age:50, gender:'boy'},
20549        {name:'Erika', age:27, gender:'girl'},
20550        {name:'Patrick', age:40, gender:'boy'},
20551        {name:'Samantha', age:60, gender:'girl'}
20552      ]">
20553        I have {{friends.length}} friends. They are:
20554        <input type="search" ng-model="q" placeholder="filter friends..." />
20555        <ul class="example-animate-container">
20556          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
20557            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
20558          </li>
20559        </ul>
20560      </div>
20561    </file>
20562    <file name="animations.css">
20563      .example-animate-container {
20564        background:white;
20565        border:1px solid black;
20566        list-style:none;
20567        margin:0;
20568        padding:0 10px;
20569      }
20570
20571      .animate-repeat {
20572        line-height:40px;
20573        list-style:none;
20574        box-sizing:border-box;
20575      }
20576
20577      .animate-repeat.ng-move,
20578      .animate-repeat.ng-enter,
20579      .animate-repeat.ng-leave {
20580        -webkit-transition:all linear 0.5s;
20581        transition:all linear 0.5s;
20582      }
20583
20584      .animate-repeat.ng-leave.ng-leave-active,
20585      .animate-repeat.ng-move,
20586      .animate-repeat.ng-enter {
20587        opacity:0;
20588        max-height:0;
20589      }
20590
20591      .animate-repeat.ng-leave,
20592      .animate-repeat.ng-move.ng-move-active,
20593      .animate-repeat.ng-enter.ng-enter-active {
20594        opacity:1;
20595        max-height:40px;
20596      }
20597    </file>
20598    <file name="protractor.js" type="protractor">
20599      var friends = element.all(by.repeater('friend in friends'));
20600
20601      it('should render initial data set', function() {
20602        expect(friends.count()).toBe(10);
20603        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
20604        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
20605        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
20606        expect(element(by.binding('friends.length')).getText())
20607            .toMatch("I have 10 friends. They are:");
20608      });
20609
20610       it('should update repeater when filter predicate changes', function() {
20611         expect(friends.count()).toBe(10);
20612
20613         element(by.model('q')).sendKeys('ma');
20614
20615         expect(friends.count()).toBe(2);
20616         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
20617         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
20618       });
20619      </file>
20620    </example>
20621 */
20622var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20623  var NG_REMOVED = '$$NG_REMOVED';
20624  var ngRepeatMinErr = minErr('ngRepeat');
20625  return {
20626    transclude: 'element',
20627    priority: 1000,
20628    terminal: true,
20629    $$tlb: true,
20630    link: function($scope, $element, $attr, ctrl, $transclude){
20631        var expression = $attr.ngRepeat;
20632        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
20633          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
20634          lhs, rhs, valueIdentifier, keyIdentifier,
20635          hashFnLocals = {$id: hashKey};
20636
20637        if (!match) {
20638          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
20639            expression);
20640        }
20641
20642        lhs = match[1];
20643        rhs = match[2];
20644        trackByExp = match[3];
20645
20646        if (trackByExp) {
20647          trackByExpGetter = $parse(trackByExp);
20648          trackByIdExpFn = function(key, value, index) {
20649            // assign key, value, and $index to the locals so that they can be used in hash functions
20650            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
20651            hashFnLocals[valueIdentifier] = value;
20652            hashFnLocals.$index = index;
20653            return trackByExpGetter($scope, hashFnLocals);
20654          };
20655        } else {
20656          trackByIdArrayFn = function(key, value) {
20657            return hashKey(value);
20658          };
20659          trackByIdObjFn = function(key) {
20660            return key;
20661          };
20662        }
20663
20664        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
20665        if (!match) {
20666          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
20667                                                                    lhs);
20668        }
20669        valueIdentifier = match[3] || match[1];
20670        keyIdentifier = match[2];
20671
20672        // Store a list of elements from previous run. This is a hash where key is the item from the
20673        // iterator, and the value is objects with following properties.
20674        //   - scope: bound scope
20675        //   - element: previous element.
20676        //   - index: position
20677        var lastBlockMap = {};
20678
20679        //watch props
20680        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
20681          var index, length,
20682              previousNode = $element[0],     // current position of the node
20683              nextNode,
20684              // Same as lastBlockMap but it has the current state. It will become the
20685              // lastBlockMap on the next iteration.
20686              nextBlockMap = {},
20687              arrayLength,
20688              childScope,
20689              key, value, // key/value of iteration
20690              trackById,
20691              trackByIdFn,
20692              collectionKeys,
20693              block,       // last object information {scope, element, id}
20694              nextBlockOrder = [],
20695              elementsToRemove;
20696
20697
20698          if (isArrayLike(collection)) {
20699            collectionKeys = collection;
20700            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
20701          } else {
20702            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
20703            // if object, extract keys, sort them and use to determine order of iteration over obj props
20704            collectionKeys = [];
20705            for (key in collection) {
20706              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
20707                collectionKeys.push(key);
20708              }
20709            }
20710            collectionKeys.sort();
20711          }
20712
20713          arrayLength = collectionKeys.length;
20714
20715          // locate existing items
20716          length = nextBlockOrder.length = collectionKeys.length;
20717          for(index = 0; index < length; index++) {
20718           key = (collection === collectionKeys) ? index : collectionKeys[index];
20719           value = collection[key];
20720           trackById = trackByIdFn(key, value, index);
20721           assertNotHasOwnProperty(trackById, '`track by` id');
20722           if(lastBlockMap.hasOwnProperty(trackById)) {
20723             block = lastBlockMap[trackById];
20724             delete lastBlockMap[trackById];
20725             nextBlockMap[trackById] = block;
20726             nextBlockOrder[index] = block;
20727           } else if (nextBlockMap.hasOwnProperty(trackById)) {
20728             // restore lastBlockMap
20729             forEach(nextBlockOrder, function(block) {
20730               if (block && block.scope) lastBlockMap[block.id] = block;
20731             });
20732             // This is a duplicate and we need to throw an error
20733             throw ngRepeatMinErr('dupes',
20734                  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
20735                  expression, trackById, toJson(value));
20736           } else {
20737             // new never before seen block
20738             nextBlockOrder[index] = { id: trackById };
20739             nextBlockMap[trackById] = false;
20740           }
20741         }
20742
20743          // remove existing items
20744          for (key in lastBlockMap) {
20745            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20746            if (lastBlockMap.hasOwnProperty(key)) {
20747              block = lastBlockMap[key];
20748              elementsToRemove = getBlockElements(block.clone);
20749              $animate.leave(elementsToRemove);
20750              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
20751              block.scope.$destroy();
20752            }
20753          }
20754
20755          // we are not using forEach for perf reasons (trying to avoid #call)
20756          for (index = 0, length = collectionKeys.length; index < length; index++) {
20757            key = (collection === collectionKeys) ? index : collectionKeys[index];
20758            value = collection[key];
20759            block = nextBlockOrder[index];
20760            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20761
20762            if (block.scope) {
20763              // if we have already seen this object, then we need to reuse the
20764              // associated scope/element
20765              childScope = block.scope;
20766
20767              nextNode = previousNode;
20768              do {
20769                nextNode = nextNode.nextSibling;
20770              } while(nextNode && nextNode[NG_REMOVED]);
20771
20772              if (getBlockStart(block) != nextNode) {
20773                // existing item which got moved
20774                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20775              }
20776              previousNode = getBlockEnd(block);
20777            } else {
20778              // new item which we don't know about
20779              childScope = $scope.$new();
20780            }
20781
20782            childScope[valueIdentifier] = value;
20783            if (keyIdentifier) childScope[keyIdentifier] = key;
20784            childScope.$index = index;
20785            childScope.$first = (index === 0);
20786            childScope.$last = (index === (arrayLength - 1));
20787            childScope.$middle = !(childScope.$first || childScope.$last);
20788            // jshint bitwise: false
20789            childScope.$odd = !(childScope.$even = (index&1) === 0);
20790            // jshint bitwise: true
20791
20792            if (!block.scope) {
20793              $transclude(childScope, function(clone) {
20794                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20795                $animate.enter(clone, null, jqLite(previousNode));
20796                previousNode = clone;
20797                block.scope = childScope;
20798                // Note: We only need the first/last node of the cloned nodes.
20799                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20800                // by a directive with templateUrl when its template arrives.
20801                block.clone = clone;
20802                nextBlockMap[block.id] = block;
20803              });
20804            }
20805          }
20806          lastBlockMap = nextBlockMap;
20807        });
20808    }
20809  };
20810
20811  function getBlockStart(block) {
20812    return block.clone[0];
20813  }
20814
20815  function getBlockEnd(block) {
20816    return block.clone[block.clone.length - 1];
20817  }
20818}];
20819
20820/**
20821 * @ngdoc directive
20822 * @name ngShow
20823 *
20824 * @description
20825 * The `ngShow` directive shows or hides the given HTML element based on the expression
20826 * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
20827 * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20828 * in AngularJS and sets the display style to none (using an !important flag).
20829 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20830 *
20831 * ```html
20832 * <!-- when $scope.myValue is truthy (element is visible) -->
20833 * <div ng-show="myValue"></div>
20834 *
20835 * <!-- when $scope.myValue is falsy (element is hidden) -->
20836 * <div ng-show="myValue" class="ng-hide"></div>
20837 * ```
20838 *
20839 * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
20840 * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
20841 * from the element causing the element not to appear hidden.
20842 *
20843 * <div class="alert alert-warning">
20844 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20845 * "f" / "0" / "false" / "no" / "n" / "[]"
20846 * </div>
20847 *
20848 * ## Why is !important used?
20849 *
20850 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
20851 * can be easily overridden by heavier selectors. For example, something as simple
20852 * as changing the display style on a HTML list item would make hidden elements appear visible.
20853 * This also becomes a bigger issue when dealing with CSS frameworks.
20854 *
20855 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20856 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20857 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20858 *
20859 * ### Overriding `.ng-hide`
20860 *
20861 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20862 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
20863 * class in CSS:
20864 *
20865 * ```css
20866 * .ng-hide {
20867 *   //this is just another form of hiding an element
20868 *   display:block!important;
20869 *   position:absolute;
20870 *   top:-9999px;
20871 *   left:-9999px;
20872 * }
20873 * ```
20874 *
20875 * By default you don't need to override in CSS anything and the animations will work around the display style.
20876 *
20877 * ## A note about animations with `ngShow`
20878 *
20879 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20880 * is true and false. This system works like the animation system present with ngClass except that
20881 * you must also include the !important flag to override the display property
20882 * so that you can perform an animation when the element is hidden during the time of the animation.
20883 *
20884 * ```css
20885 * //
20886 * //a working example can be found at the bottom of this page
20887 * //
20888 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20889 *   transition:0.5s linear all;
20890 * }
20891 *
20892 * .my-element.ng-hide-add { ... }
20893 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20894 * .my-element.ng-hide-remove { ... }
20895 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20896 * ```
20897 *
20898 * 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
20899 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20900 *
20901 * @animations
20902 * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
20903 * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
20904 *
20905 * @element ANY
20906 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20907 *     then the element is shown or hidden respectively.
20908 *
20909 * @example
20910  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20911    <file name="index.html">
20912      Click me: <input type="checkbox" ng-model="checked"><br/>
20913      <div>
20914        Show:
20915        <div class="check-element animate-show" ng-show="checked">
20916          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20917        </div>
20918      </div>
20919      <div>
20920        Hide:
20921        <div class="check-element animate-show" ng-hide="checked">
20922          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20923        </div>
20924      </div>
20925    </file>
20926    <file name="glyphicons.css">
20927      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20928    </file>
20929    <file name="animations.css">
20930      .animate-show {
20931        -webkit-transition:all linear 0.5s;
20932        transition:all linear 0.5s;
20933        line-height:20px;
20934        opacity:1;
20935        padding:10px;
20936        border:1px solid black;
20937        background:white;
20938      }
20939
20940      .animate-show.ng-hide {
20941        line-height:0;
20942        opacity:0;
20943        padding:0 10px;
20944      }
20945
20946      .check-element {
20947        padding:10px;
20948        border:1px solid black;
20949        background:white;
20950      }
20951    </file>
20952    <file name="protractor.js" type="protractor">
20953      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20954      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20955
20956      it('should check ng-show / ng-hide', function() {
20957        expect(thumbsUp.isDisplayed()).toBeFalsy();
20958        expect(thumbsDown.isDisplayed()).toBeTruthy();
20959
20960        element(by.model('checked')).click();
20961
20962        expect(thumbsUp.isDisplayed()).toBeTruthy();
20963        expect(thumbsDown.isDisplayed()).toBeFalsy();
20964      });
20965    </file>
20966  </example>
20967 */
20968var ngShowDirective = ['$animate', function($animate) {
20969  return function(scope, element, attr) {
20970    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
20971      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20972    });
20973  };
20974}];
20975
20976
20977/**
20978 * @ngdoc directive
20979 * @name ngHide
20980 *
20981 * @description
20982 * The `ngHide` directive shows or hides the given HTML element based on the expression
20983 * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
20984 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20985 * in AngularJS and sets the display style to none (using an !important flag).
20986 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20987 *
20988 * ```html
20989 * <!-- when $scope.myValue is truthy (element is hidden) -->
20990 * <div ng-hide="myValue" class="ng-hide"></div>
20991 *
20992 * <!-- when $scope.myValue is falsy (element is visible) -->
20993 * <div ng-hide="myValue"></div>
20994 * ```
20995 *
20996 * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
20997 * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
20998 * from the element causing the element not to appear hidden.
20999 *
21000 * <div class="alert alert-warning">
21001 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
21002 * "f" / "0" / "false" / "no" / "n" / "[]"
21003 * </div>
21004 *
21005 * ## Why is !important used?
21006 *
21007 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
21008 * can be easily overridden by heavier selectors. For example, something as simple
21009 * as changing the display style on a HTML list item would make hidden elements appear visible.
21010 * This also becomes a bigger issue when dealing with CSS frameworks.
21011 *
21012 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
21013 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
21014 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
21015 *
21016 * ### Overriding `.ng-hide`
21017 *
21018 * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
21019 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
21020 * class in CSS:
21021 *
21022 * ```css
21023 * .ng-hide {
21024 *   //this is just another form of hiding an element
21025 *   display:block!important;
21026 *   position:absolute;
21027 *   top:-9999px;
21028 *   left:-9999px;
21029 * }
21030 * ```
21031 *
21032 * By default you don't need to override in CSS anything and the animations will work around the display style.
21033 *
21034 * ## A note about animations with `ngHide`
21035 *
21036 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
21037 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
21038 * CSS class is added and removed for you instead of your own CSS class.
21039 *
21040 * ```css
21041 * //
21042 * //a working example can be found at the bottom of this page
21043 * //
21044 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
21045 *   transition:0.5s linear all;
21046 * }
21047 *
21048 * .my-element.ng-hide-add { ... }
21049 * .my-element.ng-hide-add.ng-hide-add-active { ... }
21050 * .my-element.ng-hide-remove { ... }
21051 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
21052 * ```
21053 *
21054 * 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
21055 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
21056 *
21057 * @animations
21058 * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
21059 * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
21060 *
21061 * @element ANY
21062 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
21063 *     the element is shown or hidden respectively.
21064 *
21065 * @example
21066  <example module="ngAnimate" deps="angular-animate.js" animations="true">
21067    <file name="index.html">
21068      Click me: <input type="checkbox" ng-model="checked"><br/>
21069      <div>
21070        Show:
21071        <div class="check-element animate-hide" ng-show="checked">
21072          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
21073        </div>
21074      </div>
21075      <div>
21076        Hide:
21077        <div class="check-element animate-hide" ng-hide="checked">
21078          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
21079        </div>
21080      </div>
21081    </file>
21082    <file name="glyphicons.css">
21083      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
21084    </file>
21085    <file name="animations.css">
21086      .animate-hide {
21087        -webkit-transition:all linear 0.5s;
21088        transition:all linear 0.5s;
21089        line-height:20px;
21090        opacity:1;
21091        padding:10px;
21092        border:1px solid black;
21093        background:white;
21094      }
21095
21096      .animate-hide.ng-hide {
21097        line-height:0;
21098        opacity:0;
21099        padding:0 10px;
21100      }
21101
21102      .check-element {
21103        padding:10px;
21104        border:1px solid black;
21105        background:white;
21106      }
21107    </file>
21108    <file name="protractor.js" type="protractor">
21109      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
21110      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
21111
21112      it('should check ng-show / ng-hide', function() {
21113        expect(thumbsUp.isDisplayed()).toBeFalsy();
21114        expect(thumbsDown.isDisplayed()).toBeTruthy();
21115
21116        element(by.model('checked')).click();
21117
21118        expect(thumbsUp.isDisplayed()).toBeTruthy();
21119        expect(thumbsDown.isDisplayed()).toBeFalsy();
21120      });
21121    </file>
21122  </example>
21123 */
21124var ngHideDirective = ['$animate', function($animate) {
21125  return function(scope, element, attr) {
21126    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
21127      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
21128    });
21129  };
21130}];
21131
21132/**
21133 * @ngdoc directive
21134 * @name ngStyle
21135 * @restrict AC
21136 *
21137 * @description
21138 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
21139 *
21140 * @element ANY
21141 * @param {expression} ngStyle
21142 *
21143 * {@link guide/expression Expression} which evals to an
21144 * object whose keys are CSS style names and values are corresponding values for those CSS
21145 * keys.
21146 *
21147 * Since some CSS style names are not valid keys for an object, they must be quoted.
21148 * See the 'background-color' style in the example below.
21149 *
21150 * @example
21151   <example>
21152     <file name="index.html">
21153        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
21154        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
21155        <input type="button" value="clear" ng-click="myStyle={}">
21156        <br/>
21157        <span ng-style="myStyle">Sample Text</span>
21158        <pre>myStyle={{myStyle}}</pre>
21159     </file>
21160     <file name="style.css">
21161       span {
21162         color: black;
21163       }
21164     </file>
21165     <file name="protractor.js" type="protractor">
21166       var colorSpan = element(by.css('span'));
21167
21168       it('should check ng-style', function() {
21169         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
21170         element(by.css('input[value=\'set color\']')).click();
21171         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
21172         element(by.css('input[value=clear]')).click();
21173         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
21174       });
21175     </file>
21176   </example>
21177 */
21178var ngStyleDirective = ngDirective(function(scope, element, attr) {
21179  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
21180    if (oldStyles && (newStyles !== oldStyles)) {
21181      forEach(oldStyles, function(val, style) { element.css(style, '');});
21182    }
21183    if (newStyles) element.css(newStyles);
21184  }, true);
21185});
21186
21187/**
21188 * @ngdoc directive
21189 * @name ngSwitch
21190 * @restrict EA
21191 *
21192 * @description
21193 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
21194 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
21195 * as specified in the template.
21196 *
21197 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
21198 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
21199 * matches the value obtained from the evaluated expression. In other words, you define a container element
21200 * (where you place the directive), place an expression on the **`on="..."` attribute**
21201 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
21202 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
21203 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
21204 * attribute is displayed.
21205 *
21206 * <div class="alert alert-info">
21207 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
21208 * as literal string values to match against.
21209 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
21209omeVal"` not against the
21210 * value of the expression `$scope.someVal`.
21211 * </div>
21212
21213 * @animations
21214 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
21215 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
21216 *
21217 * @usage
21218 *
21219 * ```
21220 * <ANY ng-switch="expression">
21221 *   <ANY ng-switch-when="matchValue1">...</ANY>
21222 *   <ANY ng-switch-when="matchValue2">...</ANY>
21223 *   <ANY ng-switch-default>...</ANY>
21224 * </ANY>
21225 * ```
21226 *
21227 *
21228 * @scope
21229 * @priority 800
21230 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
21231 * On child elements add:
21232 *
21233 * * `ngSwitchWhen`: the case statement to match against. If match then this
21234 *   case will be displayed. If the same match appears multiple times, all the
21235 *   elements will be displayed.
21236 * * `ngSwitchDefault`: the default case when no other case match. If there
21237 *   are multiple default cases, all of them will be displayed when no other
21238 *   case match.
21239 *
21240 *
21241 * @example
21242  <example module="switchExample" deps="angular-animate.js" animations="true">
21243    <file name="index.html">
21244      <div ng-controller="ExampleController">
21245        <select ng-model="selection" ng-options="item for item in items">
21246        </select>
21247        <tt>selection={{selection}}</tt>
21248        <hr/>
21249        <div class="animate-switch-container"
21250          ng-switch on="selection">
21251            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
21252            <div class="animate-switch" ng-switch-when="home">Home Span</div>
21253            <div class="animate-switch" ng-switch-default>default</div>
21254        </div>
21255      </div>
21256    </file>
21257    <file name="script.js">
21258      angular.module('switchExample', ['ngAnimate'])
21259        .controller('ExampleController', ['$scope', function($scope) {
21260          $scope.items = ['settings', 'home', 'other'];
21261          $scope.selection = $scope.items[0];
21262        }]);
21263    </file>
21264    <file name="animations.css">
21265      .animate-switch-container {
21266        position:relative;
21267        background:white;
21268        border:1px solid black;
21269        height:40px;
21270        overflow:hidden;
21271      }
21272
21273      .animate-switch {
21274        padding:10px;
21275      }
21276
21277      .animate-switch.ng-animate {
21278        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21279        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21280
21281        position:absolute;
21282        top:0;
21283        left:0;
21284        right:0;
21285        bottom:0;
21286      }
21287
21288      .animate-switch.ng-leave.ng-leave-active,
21289      .animate-switch.ng-enter {
21290        top:-50px;
21291      }
21292      .animate-switch.ng-leave,
21293      .animate-switch.ng-enter.ng-enter-active {
21294        top:0;
21295      }
21296    </file>
21297    <file name="protractor.js" type="protractor">
21298      var switchElem = element(by.css('[ng-switch]'));
21299      var select = element(by.model('selection'));
21300
21301      it('should start in settings', function() {
21302        expect(switchElem.getText()).toMatch(/Settings Div/);
21303      });
21304      it('should change to home', function() {
21305        select.all(by.css('option')).get(1).click();
21306        expect(switchElem.getText()).toMatch(/Home Span/);
21307      });
21308      it('should select default', function() {
21309        select.all(by.css('option')).get(2).click();
21310        expect(switchElem.getText()).toMatch(/default/);
21311      });
21312    </file>
21313  </example>
21314 */
21315var ngSwitchDirective = ['$animate', function($animate) {
21316  return {
21317    restrict: 'EA',
21318    require: 'ngSwitch',
21319
21320    // asks for $scope to fool the BC controller module
21321    controller: ['$scope', function ngSwitchController() {
21322     this.cases = {};
21323    }],
21324    link: function(scope, element, attr, ngSwitchController) {
21325      var watchExpr = attr.ngSwitch || attr.on,
21326          selectedTranscludes = [],
21327          selectedElements = [],
21328          previousElements = [],
21329          selectedScopes = [];
21330
21331      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
21332        var i, ii;
21333        for (i = 0, ii = previousElements.length; i < ii; ++i) {
21334          previousElements[i].remove();
21335        }
21336        previousElements.length = 0;
21337
21338        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
21339          var selected = selectedElements[i];
21340          selectedScopes[i].$destroy();
21341          previousElements[i] = selected;
21342          $animate.leave(selected, function() {
21343            previousElements.splice(i, 1);
21344          });
21345        }
21346
21347        selectedElements.length = 0;
21348        selectedScopes.length = 0;
21349
21350        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
21351          scope.$eval(attr.change);
21352          forEach(selectedTranscludes, function(selectedTransclude) {
21353            var selectedScope = scope.$new();
21354            selectedScopes.push(selectedScope);
21355            selectedTransclude.transclude(selectedScope, function(caseElement) {
21356              var anchor = selectedTransclude.element;
21357
21358              selectedElements.push(caseElement);
21359              $animate.enter(caseElement, anchor.parent(), anchor);
21360            });
21361          });
21362        }
21363      });
21364    }
21365  };
21366}];
21367
21368var ngSwitchWhenDirective = ngDirective({
21369  transclude: 'element',
21370  priority: 800,
21371  require: '^ngSwitch',
21372  link: function(scope, element, attrs, ctrl, $transclude) {
21373    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
21374    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
21375  }
21376});
21377
21378var ngSwitchDefaultDirective = ngDirective({
21379  transclude: 'element',
21380  priority: 800,
21381  require: '^ngSwitch',
21382  link: function(scope, element, attr, ctrl, $transclude) {
21383    ctrl.cases['?'] = (ctrl.cases['?'] || []);
21384    ctrl.cases['?'].push({ transclude: $transclude, element: element });
21385   }
21386});
21387
21388/**
21389 * @ngdoc directive
21390 * @name ngTransclude
21391 * @restrict AC
21392 *
21393 * @description
21394 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
21395 *
21396 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
21397 *
21398 * @element ANY
21399 *
21400 * @example
21401   <example module="transcludeExample">
21402     <file name="index.html">
21403       <script>
21404         angular.module('transcludeExample', [])
21405          .directive('pane', function(){
21406             return {
21407               restrict: 'E',
21408               transclude: true,
21409               scope: { title:'@' },
21410               template: '<div style="border: 1px solid black;">
21410' +
21411                           '<div style="background-color: gray">{{title}}</div>' +
21412                           '<div ng-transclude></div>' +
21413                         '</div>'
21414             };
21415         })
21416         .controller('ExampleController', ['$scope', function($scope) {
21417           $scope.title = 'Lorem Ipsum';
21418           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
21419         }]);
21420       </script>
21421       <div ng-controller="ExampleController">
21422         <input ng-model="title"><br>
21423         <textarea ng-model="text"></textarea> <br/>
21424         <pane title="{{title}}">{{text}}</pane>
21425       </div>
21426     </file>
21427     <file name="protractor.js" type="protractor">
21428        it('should have transcluded', function() {
21429          var titleElement = element(by.model('title'));
21430          titleElement.clear();
21431          titleElement.sendKeys('TITLE');
21432          var textElement = element(by.model('text'));
21433          textElement.clear();
21434          textElement.sendKeys('TEXT');
21435          expect(element(by.binding('title')).getText()).toEqual('TITLE');
21436          expect(element(by.binding('text')).getText()).toEqual('TEXT');
21437        });
21438     </file>
21439   </example>
21440 *
21441 */
21442var ngTranscludeDirective = ngDirective({
21443  link: function($scope, $element, $attrs, controller, $transclude) {
21444    if (!$transclude) {
21445      throw minErr('ngTransclude')('orphan',
21446       'Illegal use of ngTransclude directive in the template! ' +
21447       'No parent directive that requires a transclusion found. ' +
21448       'Element: {0}',
21449       startingTag($element));
21450    }
21451
21452    $transclude(function(clone) {
21453      $element.empty();
21454      $element.append(clone);
21455    });
21456  }
21457});
21458
21459/**
21460 * @ngdoc directive
21461 * @name script
21462 * @restrict E
21463 *
21464 * @description
21465 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
21466 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
21467 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
21468 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
21469 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
21470 *
21471 * @param {string} type Must be set to `'text/ng-template'`.
21472 * @param {string} id Cache name of the template.
21473 *
21474 * @example
21475  <example>
21476    <file name="index.html">
21477      <script type="text/ng-template" id="/tpl.html">
21478        Content of the template.
21479      </script>
21480
21481      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
21482      <div id="tpl-content" ng-include src="currentTpl"></div>
21483    </file>
21484    <file name="protractor.js" type="protractor">
21485      it('should load template defined inside script tag', function() {
21486        element(by.css('#tpl-link')).click();
21487        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
21488      });
21489    </file>
21490  </example>
21491 */
21492var scriptDirective = ['$templateCache', function($templateCache) {
21493  return {
21494    restrict: 'E',
21495    terminal: true,
21496    compile: function(element, attr) {
21497      if (attr.type == 'text/ng-template') {
21498        var templateUrl = attr.id,
21499            text = element[0].text;
21500
21501        $templateCache.put(templateUrl, text);
21502      }
21503    }
21504  };
21505}];
21506
21507var ngOptionsMinErr = minErr('ngOptions');
21508/**
21509 * @ngdoc directive
21510 * @name select
21511 * @restrict E
21512 *
21513 * @description
21514 * HTML `SELECT` element with angular data-binding.
21515 *
21516 * # `ngOptions`
21517 *
21518 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
21519 * elements for the `<select>` element using the array or object obtained by evaluating the
21520 * `ngOptions` comprehension_expression.
21521 *
21522 * When an item in the `<select>` menu is selected, the array element or object property
21523 * represented by the selected option will be bound to the model identified by the `ngModel`
21524 * directive.
21525 *
21526 * <div class="alert alert-warning">
21527 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
21528 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
21529 * </div>
21530 *
21531 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
21532 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
21533 * option. See example below for demonstration.
21534 *
21535 * <div class="alert alert-warning">
21536 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
21537 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
21538 * `select` model to be bound to a non-string value. This is because an option element can only
21539 * be bound to string values at present.
21540 * </div>
21541 *
21542 * @param {string} ngModel Assignable angular expression to data-bind to.
21543 * @param {string=} name Property name of the form under which the control is published.
21544 * @param {string=} required The control is considered valid only if value is entered.
21545 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21546 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21547 *    `required` when you want to data-bind to the `required` attribute.
21548 * @param {comprehension_expression=} ngOptions in one of the following forms:
21549 *
21550 *   * for array data sources:
21551 *     * `label` **`for`** `value` **`in`** `array`
21552 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
21553 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
21554 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
21555 *   * for object data sources:
21556 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21557 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
21558 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
21559 *     * `select` **`as`** `label` **`group by`** `group`
21560 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
21561 *
21562 * Where:
21563 *
21564 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
21565 *   * `value`: local variable which will refer to each item in the `array` or each property value
21566 *      of `object` during iteration.
21567 *   * `key`: local variable which will refer to a property name in `object` during iteration.
21568 *   * `label`: The result of this expression will be the label for `<option>` element. The
21569 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
21570 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
21571 *      element. If not specified, `select` expression will default to `value`.
21572 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
21573 *      DOM element.
21574 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
21575 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
21576 *     `value` variable (e.g. `value.propertyName`).
21577 *
21578 * @example
21579    <example module="selectExample">
21580      <file name="index.html">
21581        <script>
21582        angular.module('selectExample', [])
21583          .controller('ExampleController', ['$scope', function($scope) {
21584            $scope.colors = [
21585              {name:'black', shade:'dark'},
21586              {name:'white', shade:'light'},
21587              {name:'red', shade:'dark'},
21588              {name:'blue', shade:'dark'},
21589              {name:'yellow', shade:'light'}
21590            ];
21591            $scope.myColor = $scope.colors[2]; // red
21592          }]);
21593        </script>
21594        <div ng-controller="ExampleController">
21595          <ul>
21596            <li ng-repeat="color in colors">
21597              Name: <input ng-model="color.name">
21598              [<a href ng-click="colors.splice($index, 1)">X</a>]
21599            </li>
21600            <li>
21601              [<a href ng-click="colors.push({})">add</a>]
21602            </li>
21603          </ul>
21604          <hr/>
21605          Color (null not allowed):
21606          <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
21607
21608          Color (null allowed):
21609          <span  class="nullable">
21610            <select ng-model="myColor" ng-options="color.name for color in colors">
21611              <option value="">-- choose color --</option>
21612            </select>
21613          </span><br/>
21614
21615          Color grouped by shade:
21616          <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
21617          </select><br/>
21618
21619
21620          Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
21621          <hr/>
21622          Currently selected: {{ {selected_color:myColor}  }}
21623          <div style="border:solid 1px black; height:20px"
21624               ng-style="{'background-color':myColor.name}">
21625          </div>
21626        </div>
21627      </file>
21628      <file name="protractor.js" type="protractor">
21629         it('should check ng-options', function() {
21630           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
21631           element.all(by.model('myColor')).first().click();
21632           element.all(by.css('select[ng-model="myColor"] option')).first().click();
21633           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
21634           element(by.css('.nullable select[ng-model="myColor"]')).click();
21635           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
21636           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
21637         });
21638      </file>
21639    </example>
21640 */
21641
21642var ngOptionsDirective = valueFn({ terminal: true });
21643// jshint maxlen: false
21644var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
21645                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
21646  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]+?))?$/,
21647      nullModelCtrl = {$setViewValue: noop};
21648// jshint maxlen: 100
21649
21650  return {
21651    restrict: 'E',
21652    require: ['select', '?ngModel'],
21653    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
21654      var self = this,
21655          optionsMap = {},
21656          ngModelCtrl = nullModelCtrl,
21657          nullOption,
21658          unknownOption;
21659
21660
21661      self.databound = $attrs.ngModel;
21662
21663
21664      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
21665        ngModelCtrl = ngModelCtrl_;
21666        nullOption = nullOption_;
21667        unknownOption = unknownOption_;
21668      };
21669
21670
21671      self.addOption = function(value) {
21672        assertNotHasOwnProperty(value, '"option value"');
21673        optionsMap[value] = true;
21674
21675        if (ngModelCtrl.$viewValue == value) {
21676          $element.val(value);
21677          if (unknownOption.parent()) unknownOption.remove();
21678        }
21679      };
21680
21681
21682      self.removeOption = function(value) {
21683        if (this.hasOption(value)) {
21684          delete optionsMap[value];
21685          if (ngModelCtrl.$viewValue == value) {
21686            this.renderUnknownOption(value);
21687          }
21688        }
21689      };
21690
21691
21692      self.renderUnknownOption = function(val) {
21693        var unknownVal = '? ' + hashKey(val) + ' ?';
21694        unknownOption.val(unknownVal);
21695        $element.prepend(unknownOption);
21696        $element.val(unknownVal);
21697        unknownOption.prop('selected', true); // needed for IE
21698      };
21699
21700
21701      self.hasOption = function(value) {
21702        return optionsMap.hasOwnProperty(value);
21703      };
21704
21705      $scope.$on('$destroy', function() {
21706        // disable unknown option so that we don't do work when the whole select is being destroyed
21707        self.renderUnknownOption = noop;
21708      });
21709    }],
21710
21711    link: function(scope, element, attr, ctrls) {
21712      // if ngModel is not defined, we don't need to do anything
21713      if (!ctrls[1]) return;
21714
21715      var selectCtrl = ctrls[0],
21716          ngModelCtrl = ctrls[1],
21717          multiple = attr.multiple,
21718          optionsExp = attr.ngOptions,
21719          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21720          emptyOption,
21721          // we can't just jqLite('<option>') since jqLite is not smart enough
21722          // to create it in <select> and IE barfs otherwise.
21723          optionTemplate = jqLite(document.createElement('option')),
21724          optGroupTemplate =jqLite(document.createElement('optgroup')),
21725          unknownOption = optionTemplate.clone();
21726
21727      // find "null" option
21728      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21729        if (children[i].value === '') {
21730          emptyOption = nullOption = children.eq(i);
21731          break;
21732        }
21733      }
21734
21735      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21736
21737      // required validator
21738      if (multiple) {
21739        ngModelCtrl.$isEmpty = function(value) {
21740          return !value || value.length === 0;
21741        };
21742      }
21743
21744      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21745      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21746      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21747
21748
21749      ////////////////////////////
21750
21751
21752
21753      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21754        ngModelCtrl.$render = function() {
21755          var viewValue = ngModelCtrl.$viewValue;
21756
21757          if (selectCtrl.hasOption(viewValue)) {
21758            if (unknownOption.parent()) unknownOption.remove();
21759            selectElement.val(viewValue);
21760            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21761          } else {
21762            if (isUndefined(viewValue) && emptyOption) {
21763              selectElement.val('');
21764            } else {
21765              selectCtrl.renderUnknownOption(viewValue);
21766            }
21767          }
21768        };
21769
21770        selectElement.on('change', function() {
21771          scope.$apply(function() {
21772            if (unknownOption.parent()) unknownOption.remove();
21773            ngModelCtrl.$setViewValue(selectElement.val());
21774          });
21775        });
21776      }
21777
21778      function setupAsMultiple(scope, selectElement, ctrl) {
21779        var lastView;
21780        ctrl.$render = function() {
21781          var items = new HashMap(ctrl.$viewValue);
21782          forEach(selectElement.find('option'), function(option) {
21783            option.selected = isDefined(items.get(option.value));
21784          });
21785        };
21786
21787        // we have to do it on each watch since ngModel watches reference, but
21788        // we need to work of an array, so we need to see if anything was inserted/removed
21789        scope.$watch(function selectMultipleWatch() {
21790          if (!equals(lastView, ctrl.$viewValue)) {
21791            lastView = shallowCopy(ctrl.$viewValue);
21792            ctrl.$render();
21793          }
21794        });
21795
21796        selectElement.on('change', function() {
21797          scope.$apply(function() {
21798            var array = [];
21799            forEach(selectElement.find('option'), function(option) {
21800              if (option.selected) {
21801                array.push(option.value);
21802              }
21803            });
21804            ctrl.$setViewValue(array);
21805          });
21806        });
21807      }
21808
21809      function setupAsOptions(scope, selectElement, ctrl) {
21810        var match;
21811
21812        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21813          throw ngOptionsMinErr('iexp',
21814            "Expected expression in form of " +
21815            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21816            " but got '{0}'. Element: {1}",
21817            optionsExp, startingTag(selectElement));
21818        }
21819
21820        var displayFn = $parse(match[2] || match[1]),
21821            valueName = match[4] || match[6],
21822            keyName = match[5],
21823            groupByFn = $parse(match[3] || ''),
21824            valueFn = $parse(match[2] ? match[1] : valueName),
21825            valuesFn = $parse(match[7]),
21826            track = match[8],
21827            trackFn = track ? $parse(match[8]) : null,
21828            // This is an array of array of existing option groups in DOM.
21829            // We try to reuse these if possible
21830            // - optionGroupsCache[0] is the options with no option group
21831            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21832            optionGroupsCache = [[{element: selectElement, label:''}]];
21833
21834        if (nullOption) {
21835          // compile the element since there might be bindings in it
21836          $compile(nullOption)(scope);
21837
21838          // remove the class, which is added automatically because we recompile the element and it
21839          // becomes the compilation root
21840          nullOption.removeClass('ng-scope');
21841
21842          // we need to remove it before calling selectElement.empty() because otherwise IE will
21843          // remove the label from the element. wtf?
21844          nullOption.remove();
21845        }
21846
21847        // clear contents, we'll add what's needed based on the model
21848        selectElement.empty();
21849
21850        selectElement.on('change', function() {
21851          scope.$apply(function() {
21852            var optionGroup,
21853                collection = valuesFn(scope) || [],
21854                locals = {},
21855                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21856
21857            if (multiple) {
21858              value = [];
21859              for (groupIndex = 0, groupLength = optionGroupsCache.length;
21860                   groupIndex < groupLength;
21861                   groupIndex++) {
21862                // list of options for that group. (first item has the parent)
21863                optionGroup = optionGroupsCache[groupIndex];
21864
21865                for(index = 1, length = optionGroup.length; index < length; index++) {
21866                  if ((optionElement = optionGroup[index].element)[0].selected) {
21867                    key = optionElement.val();
21868                    if (keyName) locals[keyName] = key;
21869                    if (trackFn) {
21870                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21871                        locals[valueName] = collection[trackIndex];
21872                        if (trackFn(scope, locals) == key) break;
21873                      }
21874                    } else {
21875                      locals[valueName] = collection[key];
21876                    }
21877                    value.push(valueFn(scope, locals));
21878                  }
21879                }
21880              }
21881            } else {
21882              key = selectElement.val();
21883              if (key == '?') {
21884                value = undefined;
21885              } else if (key === ''){
21886                value = null;
21887              } else {
21888                if (trackFn) {
21889                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21890                    locals[valueName] = collection[trackIndex];
21891                    if (trackFn(scope, locals) == key) {
21892                      value = valueFn(scope, locals);
21893                      break;
21894                    }
21895                  }
21896                } else {
21897                  locals[valueName] = collection[key];
21898                  if (keyName) locals[keyName] = key;
21899                  value = valueFn(scope, locals);
21900                }
21901              }
21902            }
21903            ctrl.$setViewValue(value);
21904            render();
21905          });
21906        });
21907
21908        ctrl.$render = render;
21909
21910        scope.$watchCollection(valuesFn, render);
21911        scope.$watchCollection(function () {
21912          var locals = {},
21913              values = valuesFn(scope);
21914          if (values) {
21915            var toDisplay = new Array(values.length);
21916            for (var i = 0, ii = values.length; i < ii; i++) {
21917              locals[valueName] = values[i];
21918              toDisplay[i] = displayFn(scope, locals);
21919            }
21920            return toDisplay;
21921          }
21922        }, render);
21923
21924        if ( multiple ) {
21925          scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
21926        }
21927
21928        function getSelectedSet() {
21929          var selectedSet = false;
21930          if (multiple) {
21931            var modelValue = ctrl.$modelValue;
21932            if (trackFn && isArray(modelValue)) {
21933              selectedSet = new HashMap([]);
21934              var locals = {};
21935              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21936                locals[valueName] = modelValue[trackIndex];
21937                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21938              }
21939            } else {
21940              selectedSet = new HashMap(modelValue);
21941            }
21942          }
21943          return selectedSet;
21944        }
21945
21946
21947        function render() {
21948              // Temporary location for the option groups before we render them
21949          var optionGroups = {'':[]},
21950              optionGroupNames = [''],
21951              optionGroupName,
21952              optionGroup,
21953              option,
21954              existingParent, existingOptions, existingOption,
21955              modelValue = ctrl.$modelValue,
21956              values = valuesFn(scope) || [],
21957              keys = keyName ? sortedKeys(values) : values,
21958              key,
21959              groupLength, length,
21960              groupIndex, index,
21961              locals = {},
21962              selected,
21963              selectedSet = getSelectedSet(),
21964              lastElement,
21965              element,
21966              label;
21967
21968
21969          // We now build up the list of options we need (we merge later)
21970          for (index = 0; length = keys.length, index < length; index++) {
21971
21972            key = index;
21973            if (keyName) {
21974              key = keys[index];
21975              if ( key.charAt(0) === '$' ) continue;
21976              locals[keyName] = key;
21977            }
21978
21979            locals[valueName] = values[key];
21980
21981            optionGroupName = groupByFn(scope, locals) || '';
21982            if (!(optionGroup = optionGroups[optionGroupName])) {
21983              optionGroup = optionGroups[optionGroupName] = [];
21984              optionGroupNames.push(optionGroupName);
21985            }
21986            if (multiple) {
21987              selected = isDefined(
21988                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21989              );
21990            } else {
21991              if (trackFn) {
21992                var modelCast = {};
21993                modelCast[valueName] = modelValue;
21994                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21995              } else {
21996                selected = modelValue === valueFn(scope, locals);
21997              }
21998              selectedSet = selectedSet || selected; // see if at least one item is selected
21999            }
22000            label = displayFn(scope, locals); // what will be seen by the user
22001
22002            // doing displayFn(scope, locals) || '' overwrites zero values
22003            label = isDefined(label) ? label : '';
22004            optionGroup.push({
22005              // either the index into array or key from object
22006              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
22007              label: label,
22008              selected: selected                   // determine if we should be selected
22009            });
22010          }
22011          if (!multiple) {
22012            if (nullOption || modelValue === null) {
22013              // insert null option if we have a placeholder, or the model is null
22014              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
22015            } else if (!selectedSet) {
22016              // option could not be found, we have to insert the undefined item
22017              optionGroups[''].unshift({id:'?', label:'', selected:true});
22018            }
22019          }
22020
22021          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
22022          for (groupIndex = 0, groupLength = optionGroupNames.length;
22023               groupIndex < groupLength;
22024               groupIndex++) {
22025            // current option group name or '' if no group
22026            optionGroupName = optionGroupNames[groupIndex];
22027
22028            // list of options for that group. (first item has the parent)
22029            optionGroup = optionGroups[optionGroupName];
22030
22031            if (optionGroupsCache.length <= groupIndex) {
22032              // we need to grow the optionGroups
22033              existingParent = {
22034                element: optGroupTemplate.clone().attr('label', optionGroupName),
22035                label: optionGroup.label
22036              };
22037              existingOptions = [existingParent];
22038              optionGroupsCache.push(existingOptions);
22039              selectElement.append(existingParent.element);
22040            } else {
22041              existingOptions = optionGroupsCache[groupIndex];
22042              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
22043
22044              // update the OPTGROUP label if not the same.
22045              if (existingParent.label != optionGroupName) {
22046                existingParent.element.attr('label', existingParent.label = optionGroupName);
22047              }
22048            }
22049
22050            lastElement = null;  // start at the beginning
22051            for(index = 0, length = optionGroup.length; index < length; index++) {
22052              option = optionGroup[index];
22053              if ((existingOption = existingOptions[index+1])) {
22054                // reuse elements
22055                lastElement = existingOption.element;
22056                if (existingOption.label !== option.label) {
22057                  lastElement.text(existingOption.label = option.label);
22058                  lastElement.prop('label', existingOption.label);
22059                }
22060                if (existingOption.id !== option.id) {
22061                  lastElement.val(existingOption.id = option.id);
22062                }
22063                // lastElement.prop('selected') provided by jQuery has side-effects
22064                if (lastElement[0].selected !== option.selected) {
22065                  lastElement.prop('selected', (existingOption.selected = option.selected));
22066                  if (msie) {
22067                    // See #7692
22068                    // The selected item wouldn't visually update on IE without this.
22069                    // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
22070                    lastElement.prop('selected', existingOption.selected);
22071                  }
22072                }
22073              } else {
22074                // grow elements
22075
22076                // if it's a null option
22077                if (option.id === '' && nullOption) {
22078                  // put back the pre-compiled element
22079                  element = nullOption;
22080                } else {
22081                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
22082                  // in this version of jQuery on some browser the .text() returns a string
22083                  // rather then the element.
22084                  (element = optionTemplate.clone())
22085                      .val(option.id)
22086                      .prop('selected', option.selected)
22087                      .attr('selected', option.selected)
22088                      .prop('label', option.label)
22089                      .text(option.label);
22090                }
22091
22092                existingOptions.push(existingOption = {
22093                    element: element,
22094                    label: option.label,
22095                    id: option.id,
22096                    selected: option.selected
22097                });
22098                selectCtrl.addOption(option.label, element);
22099                if (lastElement) {
22100                  lastElement.after(element);
22101                } else {
22102                  existingParent.element.append(element);
22103                }
22104                lastElement = element;
22105              }
22106            }
22107            // remove any excessive OPTIONs in a group
22108            index++; // increment since the existingOptions[0] is parent element not OPTION
22109            while(existingOptions.length > index) {
22110              option = existingOptions.pop();
22111              selectCtrl.removeOption(option.label);
22112              option.element.remove();
22113            }
22114          }
22115          // remove any excessive OPTGROUPs from select
22116          while(optionGroupsCache.length > groupIndex) {
22117            optionGroupsCache.pop()[0].element.remove();
22118          }
22119        }
22120      }
22121    }
22122  };
22123}];
22124
22125var optionDirective = ['$interpolate', function($interpolate) {
22126  var nullSelectCtrl = {
22127    addOption: noop,
22128    removeOption: noop
22129  };
22130
22131  return {
22132    restrict: 'E',
22133    priority: 100,
22134    compile: function(element, attr) {
22135      if (isUndefined(attr.value)) {
22136        var interpolateFn = $interpolate(element.text(), true);
22137        if (!interpolateFn) {
22138          attr.$set('value', element.text());
22139        }
22140      }
22141
22142      return function (scope, element, attr) {
22143        var selectCtrlName = '$selectController',
22144            parent = element.parent(),
22145            selectCtrl = parent.data(selectCtrlName) ||
22146              parent.parent().data(selectCtrlName); // in case we are in optgroup
22147
22148        if (selectCtrl && selectCtrl.databound) {
22149          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
22150          // We don't want the view to drive the initialization of the model anyway.
22151          element.prop('selected', false);
22152        } else {
22153          selectCtrl = nullSelectCtrl;
22154        }
22155
22156        if (interpolateFn) {
22157          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
22158            attr.$set('value', newVal);
22159            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
22160            selectCtrl.addOption(newVal);
22161          });
22162        } else {
22163          selectCtrl.addOption(attr.value);
22164        }
22165
22166        element.on('$destroy', function() {
22167          selectCtrl.removeOption(attr.value);
22168        });
22169      };
22170    }
22171  };
22172}];
22173
22174var styleDirective = valueFn({
22175  restrict: 'E',
22176  terminal: true
22177});
22178
22179  if (window.angular.bootstrap) {
22180    //AngularJS is already loaded, so we can return here...
22181    console.log('WARNING: Tried to load angular more than once.');
22182    return;
22183  }
22184
22185  //try to bind to jquery now so that one can write angular.element().read()
22186  //but we will rebind on bootstrap again.
22187  bindJQuery();
22188
22189  publishExternalAPI(angular);
22190
22191  jqLite(document).ready(function() {
22192    angularInit(document, bootstrap);
22193  });
22194
22195})(window, document);
22196
22197!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.