PageSourceSearch

https://martinmoserswiss.github.io/lib/angular/angular.js

js martinmoserswiss.github.io collected 2026-10-03 09:34:27 UTC 727,582 bytes, 20,594 lines download raw bytes

1/**
2 * @license AngularJS v1.2.10
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(string, string, ...): Error} 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.10/' +
72      (module ? module + '/' : '') + code;
73    for (i = 2; i < arguments.length; i++) {
74      message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
75        encodeURIComponent(stringify(arguments[i]));
76    }
77
78    return new Error(message);
79  };
80}
81
82/* We need to tell jshint what variables are being exported */
83/* global
84    -angular,
85    -msie,
86    -jqLite,
87    -jQuery,
88    -slice,
89    -push,
90    -toString,
91    -ngMinErr,
92    -_angular,
93    -angularModule,
94    -nodeName_,
95    -uid,
96
97    -lowercase,
98    -uppercase,
99    -manualLowercase,
100    -manualUppercase,
101    -nodeName_,
102    -isArrayLike,
103    -forEach,
104    -sortedKeys,
105    -forEachSorted,
106    -reverseParams,
107    -nextUid,
108    -setHashKey,
109    -extend,
110    -int,
111    -inherit,
112    -noop,
113    -identity,
114    -valueFn,
115    -isUndefined,
116    -isDefined,
117    -isObject,
118    -isString,
119    -isNumber,
120    -isDate,
121    -isArray,
122    -isFunction,
123    -isRegExp,
124    -isWindow,
125    -isScope,
126    -isFile,
127    -isBoolean,
128    -trim,
129    -isElement,
130    -makeMap,
131    -map,
132    -size,
133    -includes,
134    -indexOf,
135    -arrayRemove,
136    -isLeafNode,
137    -copy,
138    -shallowCopy,
139    -equals,
140    -csp,
141    -concat,
142    -sliceArgs,
143    -bind,
144    -toJsonReplacer,
145    -toJson,
146    -fromJson,
147    -toBoolean,
148    -startingTag,
149    -tryDecodeURIComponent,
150    -parseKeyValue,
151    -toKeyValue,
152    -encodeUriSegment,
153    -encodeUriQuery,
154    -angularInit,
155    -bootstrap,
156    -snake_case,
157    -bindJQuery,
158    -assertArg,
159    -assertArgFn,
160    -assertNotHasOwnProperty,
161    -getter,
162    -getBlockElements,
163
164*/
165
166////////////////////////////////////
167
168/**
169 * @ngdoc function
170 * @name angular.lowercase
171 * @function
172 *
173 * @description Converts the specified string to lowercase.
174 * @param {string} string String to be converted to lowercase.
175 * @returns {string} Lowercased string.
176 */
177var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
178
179
180/**
181 * @ngdoc function
182 * @name angular.uppercase
183 * @function
184 *
185 * @description Converts the specified string to uppercase.
186 * @param {string} string String to be converted to uppercase.
187 * @returns {string} Uppercased string.
188 */
189var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
190
191
192var manualLowercase = function(s) {
193  /* jshint bitwise: false */
194  return isString(s)
195      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
196      : s;
197};
198var manualUppercase = function(s) {
199  /* jshint bitwise: false */
200  return isString(s)
201      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
202      : s;
203};
204
205
206// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
207// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
208// with correct but slower alternatives.
209if ('i' !== 'I'.toLowerCase()) {
210  lowercase = manualLowercase;
211  uppercase = manualUppercase;
212}
213
214
215var /** holds major version number for IE or NaN for real browsers */
216    msie,
217    jqLite,           // delay binding since jQuery could be loaded after us.
218    jQuery,           // delay binding
219    slice             = [].slice,
220    push              = [].push,
221    toString          = Object.prototype.toString,
222    ngMinErr          = minErr('ng'),
223
224
225    _angular          = window.angular,
226    /** @name angular */
227    angular           = window.angular || (window.angular = {}),
228    angularModule,
229    nodeName_,
230    uid               = ['0', '0', '0'];
231
232/**
233 * IE 11 changed the format of the UserAgent string.
234 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
235 */
236msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
237if (isNaN(msie)) {
238  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
239}
240
241
242/**
243 * @private
244 * @param {*} obj
245 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
246 *                   String ...)
247 */
248function isArrayLike(obj) {
249  if (obj == null || isWindow(obj)) {
250    return false;
251  }
252
253  var length = obj.length;
254
255  if (obj.nodeType === 1 && length) {
256    return true;
257  }
258
259  return isString(obj) || isArray(obj) || length === 0 ||
260         typeof length === 'number' && length > 0 && (length - 1) in obj;
261}
262
263/**
264 * @ngdoc function
265 * @name angular.forEach
266 * @function
267 *
268 * @description
269 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
270 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
271 * is the value of an object property or an array element and `key` is the object property key or
272 * array element index. Specifying a `context` for the function is optional.
273 *
274 * It is worth nothing that `.forEach` does not iterate over inherited properties because it filters
275 * using the `hasOwnProperty` method.
276 *
277   <pre>
278     var values = {name: 'misko', gender: 'male'};
279     var log = [];
280     angular.forEach(values, function(value, key){
281       this.push(key + ': ' + value);
282     }, log);
283     expect(log).toEqual(['name: misko', 'gender:male']);
284   </pre>
285 *
286 * @param {Object|Array} obj Object to iterate over.
287 * @param {Function} iterator Iterator function.
288 * @param {Object=} context Object to become context (`this`) for the iterator function.
289 * @returns {Object|Array} Reference to `obj`.
290 */
291function forEach(obj, iterator, context) {
292  var key;
293  if (obj) {
294    if (isFunction(obj)){
295      for (key in obj) {
296        // Need to check if hasOwnProperty exists,
297        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
298        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
299          iterator.call(context, obj[key], key);
300        }
301      }
302    }
302 else if (obj.forEach && obj.forEach !== forEach) {
303      obj.forEach(iterator, context);
304    } else if (isArrayLike(obj)) {
305      for (key = 0; key < obj.length; key++)
306        iterator.call(context, obj[key], key);
307    } else {
308      for (key in obj) {
309        if (obj.hasOwnProperty(key)) {
310          iterator.call(context, obj[key], key);
311        }
312      }
313    }
314  }
315  return obj;
316}
317
318function sortedKeys(obj) {
319  var keys = [];
320  for (var key in obj) {
321    if (obj.hasOwnProperty(key)) {
322      keys.push(key);
323    }
324  }
325  return keys.sort();
326}
327
328function forEachSorted(obj, iterator, context) {
329  var keys = sortedKeys(obj);
330  for ( var i = 0; i < keys.length; i++) {
331    iterator.call(context, obj[keys[i]], keys[i]);
332  }
333  return keys;
334}
335
336
337/**
338 * when using forEach the params are value, key, but it is often useful to have key, value.
339 * @param {function(string, *)} iteratorFn
340 * @returns {function(*, string)}
341 */
342function reverseParams(iteratorFn) {
343  return function(value, key) { iteratorFn(key, value); };
344}
345
346/**
347 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
348 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
349 * the number string gets longer over time, and it can also overflow, where as the nextId
350 * will grow much slower, it is a string, and it will never overflow.
351 *
352 * @returns an unique alpha-numeric string
353 */
354function nextUid() {
355  var index = uid.length;
356  var digit;
357
358  while(index) {
359    index--;
360    digit = uid[index].charCodeAt(0);
361    if (digit == 57 /*'9'*/) {
362      uid[index] = 'A';
363      return uid.join('');
364    }
365    if (digit == 90  /*'Z'*/) {
366      uid[index] = '0';
367    } else {
368      uid[index] = String.fromCharCode(digit + 1);
369      return uid.join('');
370    }
371  }
372  uid.unshift('0');
373  return uid.join('');
374}
375
376
377/**
378 * Set or clear the hashkey for an object.
379 * @param obj object
380 * @param h the hashkey (!truthy to delete the hashkey)
381 */
382function setHashKey(obj, h) {
383  if (h) {
384    obj.$$hashKey = h;
385  }
386  else {
387    delete obj.$$hashKey;
388  }
389}
390
391/**
392 * @ngdoc function
393 * @name angular.extend
394 * @function
395 *
396 * @description
397 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
398 * to `dst`. You can specify multiple `src` objects.
399 *
400 * @param {Object} dst Destination object.
401 * @param {...Object} src Source object(s).
402 * @returns {Object} Reference to `dst`.
403 */
404function extend(dst) {
405  var h = dst.$$hashKey;
406  forEach(arguments, function(obj){
407    if (obj !== dst) {
408      forEach(obj, function(value, key){
409        dst[key] = value;
410      });
411    }
412  });
413
414  setHashKey(dst,h);
415  return dst;
416}
417
418function int(str) {
419  return parseInt(str, 10);
420}
421
422
423function inherit(parent, extra) {
424  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
425}
426
427/**
428 * @ngdoc function
429 * @name angular.noop
430 * @function
431 *
432 * @description
433 * A function that performs no operations. This function can be useful when writing code in the
434 * functional style.
435   <pre>
436     function foo(callback) {
437       var result = calculateResult();
438       (callback || angular.noop)(result);
439     }
440   </pre>
441 */
442function noop() {}
443noop.$inject = [];
444
445
446/**
447 * @ngdoc function
448 * @name angular.identity
449 * @function
450 *
451 * @description
452 * A function that returns its first argument. This function is useful when writing code in the
453 * functional style.
454 *
455   <pre>
456     function transformer(transformationFn, value) {
457       return (transformationFn || angular.identity)(value);
458     };
459   </pre>
460 */
461function identity($) {return $;}
462identity.$inject = [];
463
464
465function valueFn(value) {return function() {return value;};}
466
467/**
468 * @ngdoc function
469 * @name angular.isUndefined
470 * @function
471 *
472 * @description
473 * Determines if a reference is undefined.
474 *
475 * @param {*} value Reference to check.
476 * @returns {boolean} True if `value` is undefined.
477 */
478function isUndefined(value){return typeof value === 'undefined';}
479
480
481/**
482 * @ngdoc function
483 * @name angular.isDefined
484 * @function
485 *
486 * @description
487 * Determines if a reference is defined.
488 *
489 * @param {*} value Reference to check.
490 * @returns {boolean} True if `value` is defined.
491 */
492function isDefined(value){return typeof value !== 'undefined';}
493
494
495/**
496 * @ngdoc function
497 * @name angular.isObject
498 * @function
499 *
500 * @description
501 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
502 * considered to be objects.
503 *
504 * @param {*} value Reference to check.
505 * @returns {boolean} True if `value` is an `Object` but not `null`.
506 */
507function isObject(value){return value != null && typeof value === 'object';}
508
509
510/**
511 * @ngdoc function
512 * @name angular.isString
513 * @function
514 *
515 * @description
516 * Determines if a reference is a `String`.
517 *
518 * @param {*} value Reference to check.
519 * @returns {boolean} True if `value` is a `String`.
520 */
521function isString(value){return typeof value === 'string';}
522
523
524/**
525 * @ngdoc function
526 * @name angular.isNumber
527 * @function
528 *
529 * @description
530 * Determines if a reference is a `Number`.
531 *
532 * @param {*} value Reference to check.
533 * @returns {boolean} True if `value` is a `Number`.
534 */
535function isNumber(value){return typeof value === 'number';}
536
537
538/**
539 * @ngdoc function
540 * @name angular.isDate
541 * @function
542 *
543 * @description
544 * Determines if a value is a date.
545 *
546 * @param {*} value Reference to check.
547 * @returns {boolean} True if `value` is a `Date`.
548 */
549function isDate(value){
550  return toString.call(value) === '[object Date]';
551}
552
553
554/**
555 * @ngdoc function
556 * @name angular.isArray
557 * @function
558 *
559 * @description
560 * Determines if a reference is an `Array`.
561 *
562 * @param {*} value Reference to check.
563 * @returns {boolean} True if `value` is an `Array`.
564 */
565function isArray(value) {
566  return toString.call(value) === '[object Array]';
567}
568
569
570/**
571 * @ngdoc function
572 * @name angular.isFunction
573 * @function
574 *
575 * @description
576 * Determines if a reference is a `Function`.
577 *
578 * @param {*} value Reference to check.
579 * @returns {boolean} True if `value` is a `Function`.
580 */
581function isFunction(value){return typeof value === 'function';}
582
583
584/**
585 * Determines if a value is a regular expression object.
586 *
587 * @private
588 * @param {*} value Reference to check.
589 * @returns {boolean} True if `value` is a `RegExp`.
590 */
591function isRegExp(value) {
592  return toString.call(value) === '[object RegExp]';
593}
594
595
596/**
597 * Checks if `obj` is a window object.
598 *
599 * @private
600 * @param {*} obj Object to check
601 * @returns {boolean} True if `obj` is a window obj.
602 */
603function isWindow(obj) {
604  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
605}
606
607
608function isScope(obj) {
609  return obj && obj.$evalAsync && obj.$watch;
610}
611
612
613function isFile(obj) {
614  return toString.call(obj) === '[object File]';
615}
616
617
618function isBoolean(value) {
619  return typeof value === 'boolean';
620}
621
622
623var trim = (function() {
624  // native trim is way faster: http://jsperf.com/angular-trim-test
625  // but IE doesn't have it... :-(
626  // TODO: we should move this into IE/ES5 polyfill
627  if (!String.prototype.trim) {
628    return function(value) {
629      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
630    };
631  }
632  return function(value) {
633    return isString(value) ? value.trim() : value;
634  };
635})();
636
637
638/**
639 * @ngdoc function
640 * @name angular.isElement
641 * @function
642 *
643 * @description
644 * Determines if a reference is a DOM element (or wrapped jQuery element).
645 *
646 * @param {*} value Reference to check.
647 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
648 */
649function isElement(node) {
650  return !!(node &&
651    (node.nodeName  // we are a direct element
652    || (node.on && node.find)));  // we have an on and find method part of jQuery API
653}
654
655/**
656 * @param str 'key1,key2,...'
657 * @returns {object} in the form of {key1:true, key2:true, ...}
658 */
659function makeMap(str){
660  var obj = {}, items = str.split(","), i;
661  for ( i = 0; i < items.length; i++ )
662    obj[ items[i] ] = true;
663  return obj;
664}
665
666
667if (msie < 9) {
668  nodeName_ = function(element) {
669    element = element.nodeName ? element : element[0];
670    return (element.scopeName && element.scopeName != 'HTML')
671      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
672  };
673} else {
674  nodeName_ = function(element) {
675    return element.nodeName ? element.nodeName : element[0].nodeName;
676  };
677}
678
679
680function map(obj, iterator, context) {
681  var results = [];
682  forEach(obj, function(value, index, list) {
683    results.push(iterator.call(context, value, index, list));
684  });
685  return results;
686}
687
688
689/**
690 * @description
691 * Determines the number of elements in an array, the number of properties an object has, or
692 * the length of a string.
693 *
694 * Note: This function is used to augment the Object type in Angular expressions. See
695 * {@link angular.Object} for more information about Angular arrays.
696 *
697 * @param {Object|Array|string} obj Object, array, or string to inspect.
698 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
699 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
700 */
701function size(obj, ownPropsOnly) {
702  var count = 0, key;
703
704  if (isArray(obj) || isString(obj)) {
705    return obj.length;
706  } else if (isObject(obj)){
707    for (key in obj)
708      if (!ownPropsOnly || obj.hasOwnProperty(key))
709        count++;
710  }
711
712  return count;
713}
714
715
716function includes(array, obj) {
717  return indexOf(array, obj) != -1;
718}
719
720function indexOf(array, obj) {
721  if (array.indexOf) return array.indexOf(obj);
722
723  for (var i = 0; i < array.length; i++) {
724    if (obj === array[i]) return i;
725  }
726  return -1;
727}
728
729function arrayRemove(array, value) {
730  var index = indexOf(array, value);
731  if (index >=0)
732    array.splice(index, 1);
733  return value;
734}
735
736function isLeafNode (node) {
737  if (node) {
738    switch (node.nodeName) {
739    case "OPTION":
740    case "PRE":
741    case "TITLE":
742      return true;
743    }
744  }
745  return false;
746}
747
748/**
749 * @ngdoc function
750 * @name angular.copy
751 * @function
752 *
753 * @description
754 * Creates a deep copy of `source`, which should be an object or an array.
755 *
756 * * If no destination is supplied, a copy of the object or array is created.
757 * * If a destination is provided, all of its elements (for array) or properties (for objects)
758 *   are deleted and then all elements/properties from the source are copied to it.
759 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
760 * * If `source` is identical to 'destination' an exception will be thrown.
761 *
762 * @param {*} source The source that will be used to make a copy.
763 *                   Can be any type, including primitives, `null`, and `undefined`.
764 * @param {(Object|Array)=} destination Destination into which the source is copied. If
765 *     provided, must be of the same type as `source`.
766 * @returns {*} The copy or updated `destination`, if `destination` was specified.
767 *
768 * @example
769 <doc:example>
770 <doc:source>
771 <div ng-controller="Controller">
772 <form novalidate class="simple-form">
773 Name: <input type="text" ng-model="user.name" /><br />
774 E-mail: <input type="email" ng-model="user.email" /><br />
775 Gender: <input type="radio" ng-model="user.gender" value="male" />male
776 <input type="radio" ng-model="user.gender" value="female" />female<br />
777 <button ng-click="reset()">RESET</button>
778 <button ng-click="update(user)">SAVE</button>
779 </form>
780 <pre>form = {{user | json}}</pre>
781 <pre>master = {{master | json}}</pre>
782 </div>
783
784 <script>
785 function Controller($scope) {
786    $scope.master= {};
787
788    $scope.update = function(user) {
789      // Example with 1 argument
790      $scope.master= angular.copy(user);
791    };
792
793    $scope.reset = function() {
794      // Example with 2 arguments
795      angular.copy($scope.master, $scope.user);
796    };
797
798    $scope.reset();
799  }
800 </script>
801 </doc:source>
802 </doc:example>
803 */
804function copy(source, destination){
805  if (isWindow(source) || isScope(source)) {
806    throw ngMinErr('cpws',
807      "Can't copy! Making copies of Window or Scope instances is not supported.");
808  }
809
810  if (!destination) {
811    destination = source;
812    if (source) {
813      if (isArray(source)) {
814        destination = copy(source, []);
815      } else if (isDate(source)) {
816        destination = new Date(source.getTime());
817      } else if (isRegExp(source)) {
818        destination = new RegExp(source.source);
819      } else if (isObject(source)) {
820        destination = copy(source, {});
821      }
822    }
823  } else {
824    if (source === destination) throw ngMinErr('cpi',
825      "Can't copy! Source and destination are identical.");
826    if (isArray(source)) {
827      destination.length = 0;
828      for ( var i = 0; i < source.length; i++) {
829        destination.push(copy(source[i]));
830      }
831    } else {
832      var h = destination.$$hashKey;
833      forEach(destination, function(value, key){
834        delete destination[key];
835      });
836      for ( var key in source) {
837        destination[key] = copy(source[key]);
838      }
839      setHashKey(destination,h);
840    }
841  }
842  return destination;
843}
844
845/**
846 * Create a shallow copy of an object
847 */
848function shallowCopy(src, dst) {
849  dst = dst || {};
850
851  for(var key in src) {
852    // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
853    // so we don't need to worry about using our custom hasOwnProperty here
854    if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
855      dst[key] = src[key];
856    }
857  }
858
859  return dst;
860}
861
862
863/**
864 * @ngdoc function
865 * @name angular.equals
866 * @function
867 *
868 * @description
869 * Determines if two objects or two values are equivalent. Supports value types, regular
870 * expressions, arrays and objects.
871 *
872 * Two objects or values are considered equivalent if at least one of the following is true:
873 *
874 * * Both objects or values pass `===` comparison.
875 * * Both objects or values are of the same type and all of their properties are equal by
876 *   comparing them with `angular.equals`.
877 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
878 * * Both values represent the same regular expression (In JavasScript,
879 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
880 *   representation matches).
881 *
882 * During a property comparison, properties of `function` type and properties with names
883 * that begin with `$` are ignored.
884 *
885 * Scope and DOMWindow objects are being compared only by identify (`===`).
886 *
887 * @param {*} o1 Object or value to compare.
888 * @param {*} o2 Object or value to compare.
889 * @returns {boolean} True if arguments are equal.
890 */
891function equals(o1, o2) {
892  if (o1 === o2) return true;
893  if (o1 === null || o2 === null) return false;
894  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
895  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
896  if (t1 == t2) {
897    if (t1 == 'object') {
898      if (isArray(o1)) {
899        if (!isArray(o2)) return false;
900        if ((length = o1.length) == o2.length) {
901          for(key=0; key<length; key++) {
902            if (!equals(o1[key], o2[key])) return false;
903          }
904          return true;
905        }
906      } else if (isDate(o1)) {
907        return isDate(o2) && o1.getTime() == o2.getTime();
908      } else if (isRegExp(o1) && isRegExp(o2)) {
909        return o1.toString() == o2.toString();
910      } else {
911        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
912        keySet = {};
913        for(key in o1) {
914          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
915          if (!equals(o1[key], o2[key])) return false;
916          keySet[key] = true;
917        }
918        for(key in o2) {
919          if (!keySet.hasOwnProperty(key) &&
920              key.charAt(0) !== '$' &&
921              o2[key] !== undefined &&
922              !isFunction(o2[key])) return false;
923        }
924        return true;
925      }
926    }
927  }
928  return false;
929}
930
931
932function csp() {
933  return (document.securityPolicy && document.securityPolicy.isActive) ||
934      (document.querySelector &&
935      !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
936}
937
938
939function concat(array1, array2, index) {
940  return array1.concat(slice.call(array2, index));
941}
942
943function sliceArgs(args, startIndex) {
944  return slice.call(args, startIndex || 0);
945}
946
947
948/* jshint -W101 */
949/**
950 * @ngdoc function
951 * @name angular.bind
952 * @function
953 *
954 * @description
955 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
956 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
957 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
958 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
959 *
960 * @param {Object} self Context which `fn` should be evaluated in.
961 * @param {function()} fn Function to be bound.
962 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
963 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
964 */
965/* jshint +W101 */
966function bind(self, fn) {
967  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
968  if (isFunction(fn) && !(fn instanceof RegExp)) {
969    return curryArgs.length
970      ? function() {
971          return arguments.length
972            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
973            : fn.apply(self, curryArgs);
974        }
975      : function() {
976          return arguments.length
977            ? fn.apply(self, arguments)
978            : fn.call(self);
979        };
980  } else {
981    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
982    return fn;
983  }
984}
985
986
987function toJsonReplacer(key, value) {
988  var val = value;
989
990  if (typeof key === 'string' && key.charAt(0) === '$') {
991    val = undefined;
992  } else if (isWindow(value)) {
993    val = '$WINDOW';
994  } else if (value &&  document === value) {
995    val = '$DOCUMENT';
996  } else if (isScope(value)) {
997    val = '$SCOPE';
998  }
999
1000  return val;
1001}
1002
1003
1004/**
1005 * @ngdoc function
1006 * @name angular.toJson
1007 * @function
1008 *
1009 * @description
1010 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1011 * stripped since angular uses this notation internally.
1012 *
1013 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1014 * @param {boolean=}
1014 pretty If set to true, the JSON output will contain newlines and whitespace.
1015 * @returns {string|undefined} JSON-ified string representing `obj`.
1016 */
1017function toJson(obj, pretty) {
1018  if (typeof obj === 'undefined') return undefined;
1019  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1020}
1021
1022
1023/**
1024 * @ngdoc function
1025 * @name angular.fromJson
1026 * @function
1027 *
1028 * @description
1029 * Deserializes a JSON string.
1030 *
1031 * @param {string} json JSON string to deserialize.
1032 * @returns {Object|Array|Date|string|number} Deserialized thingy.
1033 */
1034function fromJson(json) {
1035  return isString(json)
1036      ? JSON.parse(json)
1037      : json;
1038}
1039
1040
1041function toBoolean(value) {
1042  if (typeof value === 'function') {
1043    value = true;
1044  } else if (value && value.length !== 0) {
1045    var v = lowercase("" + value);
1046    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1047  } else {
1048    value = false;
1049  }
1050  return value;
1051}
1052
1053/**
1054 * @returns {string} Returns the string representation of the element.
1055 */
1056function startingTag(element) {
1057  element = jqLite(element).clone();
1058  try {
1059    // turns out IE does not let you set .html() on elements which
1060    // are not allowed to have children. So we just ignore it.
1061    element.empty();
1062  } catch(e) {}
1063  // As Per DOM Standards
1064  var TEXT_NODE = 3;
1065  var elemHtml = jqLite('<div>').append(element).html();
1066  try {
1067    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1068        elemHtml.
1069          match(/^(<[^>]+>)/)[1].
1070          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1071  } catch(e) {
1072    return lowercase(elemHtml);
1073  }
1074
1075}
1076
1077
1078/////////////////////////////////////////////////
1079
1080/**
1081 * Tries to decode the URI component without throwing an exception.
1082 *
1083 * @private
1084 * @param str value potential URI component to check.
1085 * @returns {boolean} True if `value` can be decoded
1086 * with the decodeURIComponent function.
1087 */
1088function tryDecodeURIComponent(value) {
1089  try {
1090    return decodeURIComponent(value);
1091  } catch(e) {
1092    // Ignore any invalid uri component
1093  }
1094}
1095
1096
1097/**
1098 * Parses an escaped url query string into key-value pairs.
1099 * @returns Object.<(string|boolean)>
1100 */
1101function parseKeyValue(/**string*/keyValue) {
1102  var obj = {}, key_value, key;
1103  forEach((keyValue || "").split('&'), function(keyValue){
1104    if ( keyValue ) {
1105      key_value = keyValue.split('=');
1106      key = tryDecodeURIComponent(key_value[0]);
1107      if ( isDefined(key) ) {
1108        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1109        if (!obj[key]) {
1110          obj[key] = val;
1111        } else if(isArray(obj[key])) {
1112          obj[key].push(val);
1113        } else {
1114          obj[key] = [obj[key],val];
1115        }
1116      }
1117    }
1118  });
1119  return obj;
1120}
1121
1122function toKeyValue(obj) {
1123  var parts = [];
1124  forEach(obj, function(value, key) {
1125    if (isArray(value)) {
1126      forEach(value, function(arrayValue) {
1127        parts.push(encodeUriQuery(key, true) +
1128                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1129      });
1130    } else {
1131    parts.push(encodeUriQuery(key, true) +
1132               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1133    }
1134  });
1135  return parts.length ? parts.join('&') : '';
1136}
1137
1138
1139/**
1140 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1141 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1142 * segments:
1143 *    segment       = *pchar
1144 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1145 *    pct-encoded   = "%" HEXDIG HEXDIG
1146 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1147 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1148 *                     / "*" / "+" / "," / ";" / "="
1149 */
1150function encodeUriSegment(val) {
1151  return encodeUriQuery(val, true).
1152             replace(/%26/gi, '&').
1153             replace(/%3D/gi, '=').
1154             replace(/%2B/gi, '+');
1155}
1156
1157
1158/**
1159 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1160 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1161 * encoded per http://tools.ietf.org/html/rfc3986:
1162 *    query       = *( pchar / "/" / "?" )
1163 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1164 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1165 *    pct-encoded   = "%" HEXDIG HEXDIG
1166 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1167 *                     / "*" / "+" / "," / ";" / "="
1168 */
1169function encodeUriQuery(val, pctEncodeSpaces) {
1170  return encodeURIComponent(val).
1171             replace(/%40/gi, '@').
1172             replace(/%3A/gi, ':').
1173             replace(/%24/g, '$').
1174             replace(/%2C/gi, ',').
1175             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1176}
1177
1178
1179/**
1180 * @ngdoc directive
1181 * @name ng.directive:ngApp
1182 *
1183 * @element ANY
1184 * @param {angular.Module} ngApp an optional application
1185 *   {@link angular.module module} name to load.
1186 *
1187 * @description
1188 *
1189 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1190 * designates the **root element** of the application and is typically placed near the root element
1191 * of the page - e.g. on the `<body>` or `<html>` tags.
1192 *
1193 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
1193p`
1194 * found in the document will be used to define the root element to auto-bootstrap as an
1195 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1196 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1197 *
1198 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1199 * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
1200 * should contain the application code needed or have dependencies on other modules that will
1201 * contain the code. See {@link angular.module} for more information.
1202 *
1203 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1204 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1205 * would not be resolved to `3`.
1206 *
1207 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1208 *
1209 <example module="ngAppDemo">
1210   <file name="index.html">
1211   <div ng-controller="ngAppDemoController">
1212     I can add: {{a}} + {{b}} =  {{ a+b }}
1213   </file>
1214   <file name="script.js">
1215   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1216     $scope.a = 1;
1217     $scope.b = 2;
1218   });
1219   </file>
1220 </example>
1221 *
1222 */
1223function angularInit(element, bootstrap) {
1224  var elements = [element],
1225      appElement,
1226      module,
1227      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1228      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1229
1230  function append(element) {
1231    element && elements.push(element);
1232  }
1233
1234  forEach(names, function(name) {
1235    names[name] = true;
1236    append(document.getElementById(name));
1237    name = name.replace(':', '\\:');
1238    if (element.querySelectorAll) {
1239      forEach(element.querySelectorAll('.' + name), append);
1240      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1241      forEach(element.querySelectorAll('[' + name + ']'), append);
1242    }
1243  });
1244
1245  forEach(elements, function(element) {
1246    if (!appElement) {
1247      var className = ' ' + element.className + ' ';
1248      var match = NG_APP_CLASS_REGEXP.exec(className);
1249      if (match) {
1250        appElement = element;
1251        module = (match[2] || '').replace(/\s+/g, ',');
1252      } else {
1253        forEach(element.attributes, function(attr) {
1254          if (!appElement && names[attr.name]) {
1255            appElement = element;
1256            module = attr.value;
1257          }
1258        });
1259      }
1260    }
1261  });
1262  if (appElement) {
1263    bootstrap(appElement, module ? [module] : []);
1264  }
1265}
1266
1267/**
1268 * @ngdoc function
1269 * @name angular.bootstrap
1270 * @description
1271 * Use this function to manually start up angular application.
1272 *
1273 * See: {@link guide/bootstrap Bootstrap}
1274 *
1275 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1276 * They must use {@link api/ng.directive:ngApp ngApp}.
1277 *
1278 * @param {Element} element DOM element which is the root of angular application.
1279 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1280 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1281 *     function that will be invoked by the injector as a run block.
1282 *     See: {@link angular.module modules}
1283 * @returns {AUTO.$injector} Returns the newly created injector for this app.
1284 */
1285function bootstrap(element, modules) {
1286  var doBootstrap = function() {
1287    element = jqLite(element);
1288
1289    if (element.injector()) {
1290      var tag = (element[0] === document) ? 'document' : startingTag(element);
1291      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1292    }
1293
1294    modules = modules || [];
1295    modules.unshift(['$provide', function($provide) {
1296      $provide.value('$rootElement', element);
1297    }]);
1298    modules.unshift('ng');
1299    var injector = createInjector(modules);
1300    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1301       function(scope, element, compile, injector, animate) {
1302        scope.$apply(function() {
1303          element.data('$injector', injector);
1304          compile(element)(scope);
1305        });
1306      }]
1307    );
1308    return injector;
1309  };
1310
1311  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1312
1313  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1314    return doBootstrap();
1315  }
1316
1317  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1318  angular.resumeBootstrap = function(extraModules) {
1319    forEach(extraModules, function(module) {
1320      modules.push(module);
1321    });
1322    doBootstrap();
1323  };
1324}
1325
1326var SNAKE_CASE_REGEXP = /[A-Z]/g;
1327function snake_case(name, separator){
1328  separator = separator || '_';
1329  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1330    return (pos ? separator : '') + letter.toLowerCase();
1331  });
1332}
1333
1334function bindJQuery() {
1335  // bind to jQuery if present;
1336  jQuery = window.jQuery;
1337  // reset to jQuery or default to us.
1338  if (jQuery) {
1339    jqLite = jQuery;
1340    extend(jQuery.fn, {
1341      scope: JQLitePrototype.scope,
1342      isolateScope: JQLitePrototype.isolateScope,
1343      controller: JQLitePrototype.controller,
1344      injector: JQLitePrototype.injector,
1345      inheritedData: JQLitePrototype.inheritedData
1346    });
1347    // Method signature:
1348    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1349    jqLitePatchJQueryRemove('remove', true, true, false);
1350    jqLitePatchJQueryRemove('empty', false, false, false);
1351    jqLitePatchJQueryRemove('html', false, false, true);
1352  } else {
1353    jqLite = JQLite;
1354  }
1355  angular.element = jqLite;
1356}
1357
1358/**
1359 * throw error if the argument is falsy.
1360 */
1361function assertArg(arg, name, reason) {
1362  if (!arg) {
1363    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1364  }
1365  return arg;
1366}
1367
1368function assertArgFn(arg, name, acceptArrayAnnotation) {
1369  if (acceptArrayAnnotation && isArray(arg)) {
1370      arg = arg[arg.length - 1];
1371  }
1372
1373  assertArg(isFunction(arg), name, 'not a function, got ' +
1374      (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
1375  return arg;
1376}
1377
1378/**
1379 * throw error if the name given is hasOwnProperty
1380 * @param  {String} name    the name to test
1381 * @param  {String} context the context in which the name is used, such as module or directive
1382 */
1383function assertNotHasOwnProperty(name, context) {
1384  if (name === 'hasOwnProperty') {
1385    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1386  }
1387}
1388
1389/**
1390 * Return the value accessible from the object by path. Any undefined traversals are ignored
1391 * @param {Object} obj starting object
1392 * @param {string} path path to traverse
1393 * @param {boolean=true} bindFnToScope
1394 * @returns value as accessible by path
1395 */
1396//TODO(misko): this function needs to be removed
1397function getter(obj, path, bindFnToScope) {
1398  if (!path) return obj;
1399  var keys = path.split('.');
1400  var key;
1401  var lastInstance = obj;
1402  var len = keys.length;
1403
1404  for (var i = 0; i < len; i++) {
1405    key = keys[i];
1406    if (obj) {
1407      obj = (lastInstance = obj)[key];
1408    }
1409  }
1410  if (!bindFnToScope && isFunction(obj)) {
1411    return bind(lastInstance, obj);
1412  }
1413  return obj;
1414}
1415
1416/**
1417 * Return the DOM siblings between the first and last node in the given array.
1418 * @param {Array} array like object
1419 * @returns jQlite object containing the elements
1420 */
1421function getBlockElements(nodes) {
1422  var startNode = nodes[0],
1423      endNode = nodes[nodes.length - 1];
1424  if (startNode === endNode) {
1425    return jqLite(startNode);
1426  }
1427
1428  var element = startNode;
1429  var elements = [element];
1430
1431  do {
1432    element = element.nextSibling;
1433    if (!element) break;
1434    elements.push(element);
1435  } while (element !== endNode);
1436
1437  return jqLite(elements);
1438}
1439
1440/**
1441 * @ngdoc interface
1442 * @name angular.Module
1443 * @description
1444 *
1445 * Interface for configuring angular {@link angular.module modules}.
1446 */
1447
1448function setupModuleLoader(window) {
1449
1450  var $injectorMinErr = minErr('$injector');
1451  var ngMinErr = minErr('ng');
1452
1453  function ensure(obj, name, factory) {
1454    return obj[name] || (obj[name] = factory());
1455  }
1456
1457  var angular = ensure(window, 'angular', Object);
1458
1459  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1460  angular.$$minErr = angular.$$minErr || minErr;
1461
1462  return ensure(angular, 'module', function() {
1463    /** @type {Object.<string, angular.Module>} */
1464    var modules = {};
1465
1466    /**
1467     * @ngdoc function
1468     * @name angular.module
1469     * @description
1470     *
1471     * The `angular.module` is a global place for creating, registering and retrieving Angular
1472     * modules.
1473     * All modules (angular core or 3rd party) that should be available to an application must be
1474     * registered using this mechanism.
1475     *
1476     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1477     * existing module (the name passed as the first argument to `module`) is retrieved.
1478     *
1479     *
1480     * # Module
1481     *
1482     * A module is a collection of services, directives, filters, and configuration information.
1483     * `angular.module` is used to configure the {@link AUTO.$injector $injector}.
1484     *
1485     * <pre>
1486     * // Create a new module
1487     * var myModule = angular.module('myModule', []);
1488     *
1489     * // register a new service
1490     * myModule.value('appName', 'MyCoolApp');
1491     *
1492     * // configure existing services inside initialization blocks.
1493     * myModule.config(function($locationProvider) {
1494     *   // Configure existing providers
1495     *   $locationProvider.hashPrefix('!');
1496     * });
1497     * </pre>
1498     *
1499     * Then you can create an injector and load your modules like this:
1500     *
1501     * <pre>
1502     * var injector = angular.injector(['ng', 'MyModule'])
1503     * </pre>
1504     *
1505     * However it's more likely that you'll just use
1506     * {@link ng.directive:ngApp ngApp} or
1507     * {@link angular.bootstrap} to simplify this process for you.
1508     *
1509     * @param {!string} name The name of the module to create or retrieve.
1510     * @param {Array.<string>=} requires If specified then new module is being created. If
1511     *        unspecified then the the module is being retrieved for further configuration.
1512     * @param {Function} configFn Optional configuration function for the module. Same as
1513     *        {@link angular.Module#methods_config Module#config()}.
1514     * @returns {module} new module with the {@link angular.Module} api.
1515     */
1516    return function module(name, requires, configFn) {
1517      var assertNotHasOwnProperty = function(name, context) {
1518        if (name === 'hasOwnProperty') {
1519          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1520        }
1521      };
1522
1523      assertNotHasOwnProperty(name, 'module');
1524      if (requires && modules.hasOwnProperty(name)) {
1525        modules[name] = null;
1526      }
1527      return ensure(modules, name, function() {
1528        if (!requires) {
1529          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1530             "the module name or forgot to load it. If registering a module ensure that you " +
1531             "specify the dependencies as the second argument.", name);
1532        }
1533
1534        /** @type {!Array.<Array.<*>>} */
1535        var invokeQueue = [];
1536
1537        /** @type {!Array.<Function>} */
1538        var runBlocks = [];
1539
1540        var config = invokeLater('$injector', 'invoke');
1541
1542        /** @type {angular.Module} */
1543        var moduleInstance = {
1544          // Private state
1545          _invokeQueue: invokeQueue,
1546          _runBlocks: runBlocks,
1547
1548          /**
1549           * @ngdoc property
1550           * @name angular.Module#requires
1551           * @propertyOf angular.Module
1552           * @returns {Array.<string>} List of module names which must be loaded before this module.
1553           * @description
1554           * Holds the list of modules which the injector will load before the current module is
1555           * loaded.
1556           */
1557          requires: requires,
1558
1559          /**
1560           * @ngdoc property
1561           * @name angular.Module#name
1562           * @propertyOf angular.Module
1563           * @returns {string} Name of the module.
1564           * @description
1565           */
1566          name: name,
1567
1568
1569          /**
1570           * @ngdoc method
1571           * @name angular.Module#provider
1572           * @methodOf angular.Module
1573           * @param {string} name service name
1574           * @param {Function} providerType Construction function for creating new instance of the
1575           *                                service.
1576           * @description
1577           * See {@link AUTO.$provide#provider $provide.provider()}.
1578           */
1579          provider: invokeLater('$provide', 'provider'),
1580
1581          /**
1582           * @ngdoc method
1583           * @name angular.Module#factory
1584           * @methodOf angular.Module
1585           * @param {string} name service name
1586           * @param {Function} providerFunction Function for creating new instance of the service.
1587           * @description
1588           * See {@link AUTO.$provide#factory $provide.factory()}.
1589           */
1590          factory: invokeLater('$provide', 'factory'),
1591
1592          /**
1593           * @ngdoc method
1594           * @name angular.Module#service
1595           * @methodOf angular.Module
1596           * @param {string} name service name
1597           * @param {Function} constructor A constructor function that will be instantiated.
1598           * @description
1599           * See {@link AUTO.$provide#service $provide.service()}.
1600           */
1601          service: invokeLater('$provide', 'service'),
1602
1603          /**
1604           * @ngdoc method
1605           * @name angular.Module#value
1606           * @methodOf angular.Module
1607           * @param {string} name service name
1608           * @param {*} object Service instance object.
1609           * @description
1610           * See {@link AUTO.$provide#value $provide.value()}.
1611           */
1612          value: invokeLater('$provide', 'value'),
1613
1614          /**
1615           * @ngdoc method
1616           * @name angular.Module#constant
1617           * @methodOf angular.Module
1618           * @param {string} name constant name
1619           * @param {*} object Constant value.
1620           * @description
1621           * Because the constant are fixed, they get applied before other provide methods.
1622           * See {@link AUTO.$provide#constant $provide.constant()}.
1623           */
1624          constant: invokeLater('$provide', 'constant', 'unshift'),
1625
1626          /**
1627           * @ngdoc method
1628           * @name angular.Module#animation
1629           * @methodOf angular.Module
1630           * @param {string} name animation name
1631           * @param {Function} animationFactory Factory function for creating new instance of an
1632           *                                    animation.
1633           * @description
1634           *
1635           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1636           *
1637           *
1638           * Defines an animation hook that can be later used with
1639           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1640           *
1641           * <pre>
1642           * module.animation('.animation-name', function($inject1, $inject2) {
1643           *   return {
1644           *     eventName : function(element, done) {
1645           *       //code to run the animation
1646           *       //once complete, then run done()
1647           *       return function cancellationFunction(element) {
1648           *         //code to cancel the animation
1649           *       }
1650           *     }
1651           *   }
1652           * })
1653           * </pre>
1654           *
1655           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1656           * {@link ngAnimate ngAnimate module} for more information.
1657           */
1658          animation: invokeLater('$animateProvider', 'register'),
1659
1660          /**
1661           * @ngdoc method
1662           * @name angular.Module#filter
1663           * @methodOf angular.Module
1664           * @param {string} name Filter name.
1665           * @param {Function} filterFactory Factory function for creating new instance of filter.
1666           * @description
1667           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1668           */
1669          filter: invokeLater('$filterProvider', 'register'),
1670
1671          /**
1672           * @ngdoc method
1673           * @name angular.Module#controller
1674           * @methodOf angular.Module
1675           * @param {string|Object} name Controller name, or an object map of controllers where the
1676           *    keys are the names and the values are the constructors.
1677           * @param {Function} constructor Controller constructor function.
1678           * @description
1679           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1680           */
1681          controller: invokeLater('$controllerProvider', 'register'),
1682
1683          /**
1684           * @ngdoc method
1685           * @name angular.Module#directive
1686           * @methodOf angular.Module
1687           * @param {string|Object} name Directive name, or an object map of directives where the
1688           *    keys are the names and the values are the factories.
1689           * @param {Function} directiveFactory Factory function for creating new instance of
1690           * directives.
1691           * @description
1692           * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
1693           */
1694          directive: invokeLater('$compileProvider', 'directive'),
1695
1696          /**
1697           * @ngdoc method
1698           * @name angular.Module#config
1699           * @methodOf angular.Module
1700           * @param {Function} configFn Execute this function on module load. Useful for service
1701           *    configuration.
1702           * @description
1703           * Use this method to register work which needs to be performed on module loading.
1704           */
1705          config: config,
1706
1707          /**
1708           * @ngdoc method
1709           * @name angular.Module#run
1710           * @methodOf angular.Module
1711           * @param {Function} initializationFn Execute this function after injector creation.
1712           *    Useful for application initialization.
1713           * @description
1714           * Use this method to register work which should be performed when the injector is done
1715           * loading all modules.
1716           */
1717          run: function(block) {
1718            runBlocks.push(block);
1719            return this;
1720          }
1721        };
1722
1723        if (configFn) {
1724          config(configFn);
1725        }
1726
1727        return  moduleInstance;
1728
1729        /**
1730         * @param {string} provider
1731         * @param {string} method
1732         * @param {String=} insertMethod
1733         * @returns {angular.Module}
1734         */
1735        function invokeLater(provider, method, insertMethod) {
1736          return function() {
1737            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1738            return moduleInstance;
1739          };
1740        }
1741      });
1742    };
1743  });
1744
1745}
1746
1747/* global
1748    angularModule: true,
1749    version: true,
1750    
1751    $LocaleProvider,
1752    $CompileProvider,
1753    
1754    htmlAnchorDirective,
1755    inputDirective,
1756    inputDirective,
1757    formDirective,
1758    scriptDirective,
1759    selectDirective,
1760    styleDirective,
1761    optionDirective,
1762    ngBindDirective,
1763    ngBindHtmlDirective,
1764    ngBindTemplateDirective,
1765    ngClassDirective,
1766    ngClassEvenDirective,
1767    ngClassOddDirective,
1768    ngCspDirective,
1769    ngCloakDirective,
1770    ngControllerDirective,
1771    ngFormDirective,
1772    ngHideDirective,
1773    ngIfDirective,
1774    ngIncludeDirective,
1775    ngIncludeFillContentDirective,
1776    ngInitDirective,
1777    ngNonBindableDirective,
1778    ngPluralizeDirective,
1779    ngRepeatDirective,
1780    ngShowDirective,
1781    ngStyleDirective,
1782    ngSwitchDirective,
1783    ngSwitchWhenDirective,
1784    ngSwitchDefaultDirective,
1785    ngOptionsDirective,
1786    ngTranscludeDirective,
1787    ngModelDirective,
1788    ngListDirective,
1789    ngChangeDirective,
1790    requiredDirective,
1791    requiredDirective,
1792    ngValueDirective,
1793    ngAttributeAliasDirectives,
1794    ngEventDirectives,
1795
1796    $AnchorScrollProvider,
1797    $AnimateProvider,
1798    $BrowserProvider,
1799    $CacheFactoryProvider,
1800    $ControllerProvider,
1801    $DocumentProvider,
1802    $ExceptionHandlerProvider,
1803    $FilterProvider,
1804    $InterpolateProvider,
1805    $IntervalProvider,
1806    $HttpProvider,
1807    $HttpBackendProvider,
1808    $LocationProvider,
1809    $LogProvider,
1810    $ParseProvider,
1811    $RootScopeProvider,
1812    $QProvider,
1813    $$SanitizeUriProvider,
1814    $SceProvider,
1815    $SceDelegateProvider,
1816    $SnifferProvider,
1817    $TemplateCacheProvider,
1818    $TimeoutProvider,
1819    $WindowProvider
1820*/
1821
1822
1823/**
1824 * @ngdoc property
1825 * @name angular.version
1826 * @description
1827 * An object that contains information about the current AngularJS version. This object has the
1828 * following properties:
1829 *
1830 * - `full` – `{string}` – Full version string, such as "0.9.18".
1831 * - `major` – `{number}` – Major version number, such as "0".
1832 * - `minor` – `{number}` – Minor version number, such as "9".
1833 * - `dot` – `{number}` – Dot version number, such as "18".
1834 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1835 */
1836var version = {
1837  full: '1.2.10',    // all of these placeholder strings will be replaced by grunt's
1838  major: 1,    // package task
1839  minor: 2,
1840  dot: 10,
1841  codeName: 'augmented-serendipity'
1842};
1843
1844
1845function publishExternalAPI(angular){
1846  extend(angular, {
1847    'bootstrap': bootstrap,
1848    'copy': copy,
1849    'extend': extend,
1850    'equals': equals,
1851    'element': jqLite,
1852    'forEach': forEach,
1853    'injector': createInjector,
1854    'noop':noop,
1855    'bind':bind,
1856    'toJson': toJson,
1857    'fromJson': fromJson,
1858    'identity':identity,
1859    'isUndefined': isUndefined,
1860    'isDefined': isDefined,
1861    'isString': isString,
1862    'isFunction': isFunction,
1863    'isObject': isObject,
1864    'isNumber': isNumber,
1865    'isElement': isElement,
1866    'isArray': isArray,
1867    'version': version,
1868    'isDate': isDate,
1869    'lowercase': lowercase,
1870    'uppercase': uppercase,
1871    'callbacks': {counter: 0},
1872    '$$minErr': minErr,
1873    '$$csp': csp
1874  });
1875
1876  angularModule = setupModuleLoader(window);
1877  try {
1878    angularModule('ngLocale');
1879  } catch (e) {
1880    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
1881  }
1882
1883  angularModule('ng', ['ngLocale'], ['$provide',
1884    function ngModule($provide) {
1885      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
1886      $provide.provider({
1887        $$sanitizeUri: $$SanitizeUriProvider
1888      });
1889      $provide.provider('$compile', $CompileProvider).
1890        directive({
1891            a: htmlAnchorDirective,
1892            input: inputDirective,
1893            textarea: inputDirective,
1894            form: formDirective,
1895            script: scriptDirective,
1896            select: selectDirective,
1897            style: styleDirective,
1898            option: optionDirective,
1899            ngBind: ngBindDirective,
1900            ngBindHtml: ngBindHtmlDirective,
1901            ngBindTemplate: ngBindTemplateDirective,
1902            ngClass: ngClassDirective,
1903            ngClassEven: ngClassEvenDirective,
1904            ngClassOdd: ngClassOddDirective,
1905            ngCloak: ngCloakDirective,
1906            ngController: ngControllerDirective,
1907            ngForm: ngFormDirective,
1908            ngHide: ngHideDirective,
1909            ngIf: ngIfDirective,
1910            ngInclude: ngIncludeDirective,
1911            ngInit: ngInitDirective,
1912            ngNonBindable: ngNonBindableDirective,
1913            ngPluralize: ngPluralizeDirective,
1914            ngRepeat: ngRepeatDirective,
1915            ngShow: ngShowDirective,
1916            ngStyle: ngStyleDirective,
1917            ngSwitch: ngSwitchDirective,
1918            ngSwitchWhen: ngSwitchWhenDirective,
1919            ngSwitchDefault: ngSwitchDefaultDirective,
1920            ngOptions: ngOptionsDirective,
1921            ngTransclude: ngTranscludeDirective,
1922            ngModel: ngModelDirective,
1923            ngList: ngListDirective,
1924            ngChange: ngChangeDirective,
1925            required: requiredDirective,
1926            ngRequired: requiredDirective,
1927            ngValue: ngValueDirective
1928        }).
1929        directive({
1930          ngInclude: ngIncludeFillContentDirective
1931        }).
1932        directive(ngAttributeAliasDirectives).
1933        directive(ngEventDirectives);
1934      $provide.provider({
1935        $anchorScroll: $AnchorScrollProvider,
1936        $animate: $AnimateProvider,
1937        $browser: $BrowserProvider,
1938        $cacheFactory: $CacheFactoryProvider,
1939        $controller: $ControllerProvider,
1940        $document: $DocumentProvider,
1941        $exceptionHandler: $ExceptionHandlerProvider,
1942        $filter: $FilterProvider,
1943        $interpolate: $InterpolateProvider,
1944        $interval: $IntervalProvider,
1945        $http: $HttpProvider,
1946        $httpBackend: $HttpBackendProvider,
1947        $location: $LocationProvider,
1948        $log: $LogProvider,
1949        $parse: $ParseProvider,
1950        $rootScope: $RootScopeProvider,
1951        $q: $QProvider,
1952        $sce: $SceProvider,
1953        $sceDelegate: $SceDelegateProvider,
1954        $sniffer: $SnifferProvider,
1955        $templateCache: $TemplateCacheProvider,
1956        $timeout: $TimeoutProvider,
1957        $window: $WindowProvider
1958      });
1959    }
1960  ]);
1961}
1962
1963/* global
1964
1965  -JQLitePrototype,
1966  -addEventListenerFn,
1967  -removeEventListenerFn,
1968  -BOOLEAN_ATTR
1969*/
1970
1971//////////////////////////////////
1972//JQLite
1973//////////////////////////////////
1974
1975/**
1976 * @ngdoc function
1977 * @name angular.element
1978 * @function
1979 *
1980 * @description
1981 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
1982 *
1983 * If jQuery is available, `angular.element` is an alias for the
1984 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
1985 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
1986 *
1987 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
1988 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
1989 * commonly needed functionality with the goal of having a very small footprint.</div>
1990 *
1991 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
1992 *
1993 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
1994 * jqLite; they are never raw DOM references.</div>
1995 *
1996 * ## Angular's jqLite
1997 * jqLite provides only the following jQuery methods:
1998 *
1999 * - [`addClass()`](http://api.jquery.com/addClass/)
2000 * - [`after()`](http://api.jquery.com/after/)
2001 * - [`append()`](http://api.jquery.com/append/)
2002 * - [`attr()`](http://api.jquery.com/attr/)
2003 * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2004 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2005 * - [`clone()`](http://api.jquery.com/clone/)
2006 * - [`contents()`](http://api.jquery.com/contents/)
2007 * - [`css()`](http://api.jquery.com/css/)
2008 * - [`data()`](http://api.jquery.com/data/)
2009 * - [`empty()`](http://api.jquery.com/empty/)
2010 * - [`eq()`](http://api.jquery.com/eq/)
2011 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2012 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2013 * - [`html()`](http://api.jquery.com/html/)
2014 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2015 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2016 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2017 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2018 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2019 * - [`prepend()`](http://api.jquery.com/prepend/)
2020 * - [`prop()`](http://api.jquery.com/prop/)
2021 * - [`ready()`](http://api.jquery.com/ready/)
2022 * - [`remove()`](http://api.jquery.com/remove/)
2023 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2024 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2025 * - [`removeData()`](http://api.jquery.com/removeData/)
2026 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2027 * - [`text()`](http://api.jquery.com/text/)
2028 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2029 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2030 * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces
2031 * - [`val()`](http://api.jquery.com/val/)
2032 * - [`wrap()`](http://api.jquery.com/wrap/)
2033 *
2034 * ## jQuery/jqLite Extras
2035 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2036 *
2037 * ### Events
2038 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2039 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2040 *    element before it is removed.
2041 *
2042 * ### Methods
2043 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2044 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2045 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2046 *   `'ngModel'`).
2047 * - `injector()` - retrieves the injector of the current element or its parent.
2048 * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
2049 *   element or its parent.
2050 * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the
2051 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2052 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2053 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2054 *   parent element is reached.
2055 *
2056 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2057 * @returns {Object} jQuery object.
2058 */
2059
2060var jqCache = JQLite.cache = {},
2061    jqName = JQLite.expando = 'ng-' + new Date().getTime(),
2062    jqId = 1,
2063    addEventListenerFn = (window.document.addEventListener
2064      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2065      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2066    removeEventListenerFn = (window.document.removeEventListener
2067      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2068      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2069
2070function jqNextId() { return ++jqId; }
2071
2072
2073var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2074var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2075var jqLiteMinErr = minErr('jqLite');
2076
2077/**
2078 * Converts snake_case to camelCase.
2079 * Also there is special case for Moz prefix starting with upper case letter.
2080 * @param name Name to normalize
2081 */
2082function camelCase(name) {
2083  return name.
2084    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2085      return offset ? letter.toUpperCase() : letter;
2086    }).
2087    replace(MOZ_HACK_REGEXP, 'Moz$1');
2088}
2089
2090/////////////////////////////////////////////
2091// jQuery mutation patch
2092//
2093// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2094// $destroy event on all DOM nodes being removed.
2095//
2096/////////////////////////////////////////////
2097
2098function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2099  var originalJqFn = jQuery.fn[name];
2100  originalJqFn = originalJqFn.$original || originalJqFn;
2101  removePatch.$original = originalJqFn;
2102  jQuery.fn[name] = removePatch;
2103
2104  function removePatch(param) {
2105    // jshint -W040
2106    var list = filterElems && param ? [this.filter(param)] : [this],
2107        fireEvent = dispatchThis,
2108        set, setIndex, setLength,
2109        element, childIndex, childLength, children;
2110
2111    if (!getterIfNoArguments || param != null) {
2112      while(list.length) {
2113        set = list.shift();
2114        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2115          element = jqLite(set[setIndex]);
2116          if (fireEvent) {
2117            element.triggerHandler('$destroy');
2118          } else {
2119            fireEvent = !fireEvent;
2120          }
2121          for(childIndex = 0, childLength = (children = element.children()).length;
2122              childIndex < childLength;
2123              childIndex++) {
2124            list.push(jQuery(children[childIndex]));
2125          }
2126        }
2127      }
2128    }
2129    return originalJqFn.apply(this, arguments);
2130  }
2131}
2132
2133/////////////////////////////////////////////
2134function JQLite(element) {
2135  if (element instanceof JQLite) {
2136    return element;
2137  }
2138  if (!(this instanceof JQLite)) {
2139    if (isString(element) && element.charAt(0) != '<') {
2140      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2141    }
2142    return new JQLite(element);
2143  }
2144
2145  if (isString(element)) {
2146    var div = document.createElement('div');
2147    // Read about the NoScope elements here:
2148    // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
2149    div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
2150    div.removeChild(div.firstChild); // remove the superfluous div
2151    jqLiteAddNodes(this, div.childNodes);
2152    var fragment = jqLite(document.createDocumentFragment());
2153    fragment.append(this); // detach the elements from the temporary DOM div.
2154  } else {
2155    jqLiteAddNodes(this, element);
2156  }
2157}
2158
2159function jqLiteClone(element) {
2160  return element.cloneNode(true);
2161}
2162
2163function jqLiteDealoc(element){
2164  jqLiteRemoveData(element);
2165  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2166    jqLiteDealoc(children[i]);
2167  }
2168}
2169
2170function jqLiteOff(element, type, fn, unsupported) {
2171  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2172
2173  var events = jqLiteExpandoStore(element, 'events'),
2174      handle = jqLiteExpandoStore(element, 'handle');
2175
2176  if (!handle) return; //no listeners registered
2177
2178  if (isUndefined(type)) {
2179    forEach(events, function(eventHandler, type) {
2180      removeEventListenerFn(element, type, eventHandler);
2181      delete events[type];
2182    });
2183  } else {
2184    forEach(type.split(' '), function(type) {
2185      if (isUndefined(fn)) {
2186        removeEventListenerFn(element, type, events[type]);
2187        delete events[type];
2188      } else {
2189        arrayRemove(events[type] || [], fn);
2190      }
2191    });
2192  }
2193}
2194
2195function jqLiteRemoveData(element, name) {
2196  var expandoId = element[jqName],
2197      expandoStore = jqCache[expandoId];
2198
2199  if (expandoStore) {
2200    if (name) {
2201      delete jqCache[expandoId].data[name];
2202      return;
2203    }
2204
2205    if (expandoStore.handle) {
2206      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2207      jqLiteOff(element);
2208    }
2209    delete jqCache[expandoId];
2210    element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
2211  }
2212}
2213
2214function jqLiteExpandoStore(element, key, value) {
2215  var expandoId = element[jqName],
2216      expandoStore = jqCache[expandoId || -1];
2217
2218  if (isDefined(value)) {
2219    if (!expandoStore) {
2220      element[jqName] = expandoId = jqNextId();
2221      expandoStore = jqCache[expandoId] = {};
2222    }
2223    expandoStore[key] = value;
2224  } else {
2225    return expandoStore && expandoStore[key];
2226  }
2227}
2228
2229function jqLiteData(element, key, value) {
2230  var data = jqLiteExpandoStore(element, 'data'),
2231      isSetter = isDefined(value),
2232      keyDefined = !isSetter && isDefined(key),
2233      isSimpleGetter = keyDefined && !isObject(key);
2234
2235  if (!data && !isSimpleGetter) {
2236    jqLiteExpandoStore(element, 'data', data = {});
2237  }
2238
2239  if (isSetter) {
2240    data[key] = value;
2241  } else {
2242    if (keyDefined) {
2243      if (isSimpleGetter) {
2244        // don't create data in this case.
2245        return data && data[key];
2246      } else {
2247        extend(data, key);
2248      }
2249    } else {
2250      return data;
2251    }
2252  }
2253}
2254
2255function jqLiteHasClass(element, selector) {
2256  if (!element.getAttribute) return false;
2257  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2258      indexOf( " " + selector + " " ) > -1);
2259}
2260
2261function jqLiteRemoveClass(element, cssClasses) {
2262  if (cssClasses && element.setAttribute) {
2263    forEach(cssClasses.split(' '), function(cssClass) {
2264      element.setAttribute('class', trim(
2265          (" " + (element.getAttribute('class') || '') + " ")
2266          .replace(/[\n\t]/g, " ")
2267          .replace(" " + trim(cssClass) + " ", " "))
2268      );
2269    });
2270  }
2271}
2272
2273function jqLiteAddClass(element, cssClasses) {
2274  if (cssClasses && element.setAttribute) {
2275    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2276                            .replace(/[\n\t]/g, " ");
2277
2278    forEach(cssClasses.split(' '), function(cssClass) {
2279      cssClass = trim(cssClass);
2280      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2281        existingClasses += cssClass + ' ';
2282      }
2283    });
2284
2285    element.setAttribute('class', trim(existingClasses));
2286  }
2287}
2288
2289function jqLiteAddNodes(root, elements) {
2290  if (elements) {
2291    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2292      ? elements
2293      : [ elements ];
2294    for(var i=0; i < elements.length; i++) {
2295      root.push(elements[i]);
2296    }
2297  }
2298}
2299
2300function jqLiteController(element, name) {
2301  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2302}
2303
2304function jqLiteInheritedData(element, name, value) {
2305  element = jqLite(element);
2306
2307  // if element is the document object work with the html element instead
2308  // this makes $(document).scope() possible
2309  if(element[0].nodeType == 9) {
2310    element = element.find('html');
2311  }
2312  var names = isArray(name) ? name : [name];
2313
2314  while (element.length) {
2315
2316    for (var i = 0, ii = names.length; i < ii; i++) {
2317      if ((value = element.data(names[i])) !== undefined) return value;
2318    }
2319    element = element.parent();
2320  }
2321}
2322
2323function jqLiteEmpty(element) {
2324  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2325    jqLiteDealoc(childNodes[i]);
2326  }
2327  while (element.firstChild) {
2328    element.removeChild(element.firstChild);
2329  }
2330}
2331
2332//////////////////////////////////////////
2333// Functions which are declared directly.
2334//////////////////////////////////////////
2335var JQLitePrototype = JQLite.prototype = {
2336  ready: function(fn) {
2337    var fired = false;
2338
2339    function trigger() {
2340      if (fired) return;
2341      fired = true;
2342      fn();
2343    }
2344
2345    // check if document already is loaded
2346    if (document.readyState === 'complete'){
2347      setTimeout(trigger);
2348    } else {
2349      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2350      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2351      // jshint -W064
2352      JQLite(window).on('load', trigger); // fallback to window.onload for others
2353      // jshint +W064
2354    }
2355  },
2356  toString: function() {
2357    var value = [];
2358    forEach(this, function(e){ value.push('' + e);});
2359    return '[' + value.join(', ') + ']';
2360  },
2361
2362  eq: function(index) {
2363      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2364  },
2365
2366  length: 0,
2367  push: push,
2368  sort: [].sort,
2369  splice: [].splice
2370};
2371
2372//////////////////////////////////////////
2373// Functions iterating getter/setters.
2374// these functions return self on setter and
2375// value on get.
2376//////////////////////////////////////////
2377var BOOLEAN_ATTR = {};
2378forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2379  BOOLEAN_ATTR[lowercase(value)] = value;
2380});
2381var BOOLEAN_ELEMENTS = {};
2382forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2383  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2384});
2385
2386function getBooleanAttrName(element, name) {
2387  // check dom last since we will most likely fail on name
2388  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2389
2390  // booleanAttr is here twice to minimize DOM access
2391  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2392}
2393
2394forEach({
2395  data: jqLiteData,
2396  inheritedData: jqLiteInheritedData,
2397
2398  scope: function(element) {
2399    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2400    return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2401  },
2402
2403  isolateScope: function(element) {
2404    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2405    return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
2406  },
2407
2408  controller: jqLiteController ,
2409
2410  injector: function(element) {
2411    return jqLiteInheritedData(element, '$injector');
2412  },
2413
2414  removeAttr: function(element,name) {
2415    element.removeAttribute(name);
2416  },
2417
2418  hasClass: jqLiteHasClass,
2419
2420  css: function(element, name, value) {
2421    name = camelCase(name);
2422
2423    if (isDefined(value)) {
2424      element.style[name] = value;
2425    } else {
2426      var val;
2427
2428      if (msie <= 8) {
2429        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2430        val = element.currentStyle && element.currentStyle[name];
2431        if (val === '') val = 'auto';
2432      }
2433
2434      val = val || element.style[name];
2435
2436      if (msie <= 8) {
2437        // jquery weirdness :-/
2438        val = (val === '') ? undefined : val;
2439      }
2440
2441      return  val;
2442    }
2443  },
2444
2445  attr: function(element, name, value){
2446    var lowercasedName = lowercase(name);
2447    if (BOOLEAN_ATTR[lowercasedName]) {
2448      if (isDefined(value)) {
2449        if (!!value) {
2450          element[name] = true;
2451          element.setAttribute(name, lowercasedName);
2452        } else {
2453          element[name] = false;
2454          element.removeAttribute(lowercasedName);
2455        }
2456      } else {
2457        return (element[name] ||
2458                 (element.attributes.getNamedItem(name)|| noop).specified)
2459               ? lowercasedName
2460               : undefined;
2461      }
2462    } else if (isDefined(value)) {
2463      element.setAttribute(name, value);
2464    } else if (element.getAttribute) {
2465      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2466      // some elements (e.g. Document) don't have get attribute, so return undefined
2467      var ret = element.getAttribute(name, 2);
2468      // normalize non-existing attributes to undefined (as jQuery)
2469      return ret === null ? undefined : ret;
2470    }
2471  },
2472
2473  prop: function(element, name, value) {
2474    if (isDefined(value)) {
2475      element[name] = value;
2476    } else {
2477      return element[name];
2478    }
2479  },
2480
2481  text: (function() {
2482    var NODE_TYPE_TEXT_PROPERTY = [];
2483    if (msie < 9) {
2484      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2485      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2486    } else {
2487      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2488      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2489    }
2490    getText.$dv = '';
2491    return getText;
2492
2493    function getText(element, value) {
2494      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2495      if (isUndefined(value)) {
2496        return textProp ? element[textProp] : '';
2497      }
2498      element[textProp] = value;
2499    }
2500  })(),
2501
2502  val: function(element, value) {
2503    if (isUndefined(value)) {
2504      if (nodeName_(element) === 'SELECT' && element.multiple) {
2505        var result = [];
2506        forEach(element.options, function (option) {
2507          if (option.selected) {
2508            result.push(option.value || option.text);
2509          }
2510        });
2511        return result.length === 0 ? null : result;
2512      }
2513      return element.value;
2514    }
2515    element.value = value;
2516  },
2517
2518  html: function(element, value) {
2519    if (isUndefined(value)) {
2520      return element.innerHTML;
2521    }
2522    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2523      jqLiteDealoc(childNodes[i]);
2524    }
2525    element.innerHTML = value;
2526  },
2527
2528  empty: jqLiteEmpty
2529}, function(fn, name){
2530  /**
2531   * Properties: writes return selection, reads return first value
2532   */
2533  JQLite.prototype[name] = function(arg1, arg2) {
2534    var i, key;
2535
2536    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2537    // in a way that survives minification.
2538    // jqLiteEmpty takes no arguments but is a setter.
2539    if (fn !== jqLiteEmpty &&
2540        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2541      if (isObject(arg1)) {
2542
2543        // we are a write, but the object properties are the key/values
2544        for (i = 0; i < this.length; i++) {
2545          if (fn === jqLiteData) {
2546            // data() takes the whole object in jQuery
2547            fn(this[i], arg1);
2548          } else {
2549            for (key in arg1) {
2550              fn(this[i], key, arg1[key]);
2551            }
2552          }
2553        }
2554        // return self for chaining
2555        return this;
2556      } else {
2557        // we are a read, so read the first child.
2558        var value = fn.$dv;
2559        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2560        var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
2561        for (var j = 0; j < jj; j++) {
2562          var nodeValue = fn(this[j], arg1, arg2);
2563          value = value ? value + nodeValue : nodeValue;
2564        }
2565        return value;
2566      }
2567    } else {
2568      // we are a write, so apply to all children
2569      for (i = 0; i < this.length; i++) {
2570        fn(this[i], arg1, arg2);
2571      }
2572      // return self for chaining
2573      return this;
2574    }
2575  };
2576});
2577
2578function createEventHandler(element, events) {
2579  var eventHandler = function (event, type) {
2580    if (!event.preventDefault) {
2581      event.preventDefault = function() {
2582        event.returnValue = false; //ie
2583      };
2584    }
2585
2586    if (!event.stopPropagation) {
2587      event.stopPropagation = function() {
2588        event.cancelBubble = true; //ie
2589      };
2590    }
2591
2592    if (!event.target) {
2593      event.target = event.srcElement || document;
2594    }
2595
2596    if (isUndefined(event.defaultPrevented)) {
2597      var prevent = event.preventDefault;
2598      event.preventDefault = function() {
2599        event.defaultPrevented = true;
2600        prevent.call(event);
2601      };
2602      event.defaultPrevented = false;
2603    }
2604
2605    event.isDefaultPrevented = function() {
2606      return event.defaultPrevented || event.returnValue === false;
2607    };
2608
2609    // Copy event handlers in case event handlers array is modified during execution.
2610    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2611
2612    forEach(eventHandlersCopy, function(fn) {
2613      fn.call(element, event);
2614    });
2615
2616    // Remove monkey-patched methods (IE),
2617    // as they would cause memory leaks in IE8.
2618    if (msie <= 8) {
2619      // IE7/8 does not allow to delete property on native object
2620      event.preventDefault = null;
2621      event.stopPropagation = null;
2622      event.isDefaultPrevented = null;
2623    } else {
2624      // It shouldn't affect normal browsers (native methods are defined on prototype).
2625      delete event.preventDefault;
2626      delete event.stopPropagation;
2627      delete event.isDefaultPrevented;
2628    }
2629  };
2630  eventHandler.elem = element;
2631  return eventHandler;
2632}
2633
2634//////////////////////////////////////////
2635// Functions iterating traversal.
2636// These functions chain results into a single
2637// selector.
2638//////////////////////////////////////////
2639forEach({
2640  removeData: jqLiteRemoveData,
2641
2642  dealoc: jqLiteDealoc,
2643
2644  on: function onFn(element, type, fn, unsupported){
2645    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2646
2647    var events = jqLiteExpandoStore(element, 'events'),
2648        handle = jqLiteExpandoStore(element, 'handle');
2649
2650    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2651    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2652
2653    forEach(type.split(' '), function(type){
2654      var eventFns = events[type];
2655
2656      if (!eventFns) {
2657        if (type == 'mouseenter' || type == 'mouseleave') {
2658          var contains = document.body.contains || document.body.compareDocumentPosition ?
2659          function( a, b ) {
2660            // jshint bitwise: false
2661            var adown = a.nodeType === 9 ? a.documentElement : a,
2662            bup = b && b.parentNode;
2663            return a === bup || !!( bup && bup.nodeType === 1 && (
2664              adown.contains ?
2665              adown.contains( bup ) :
2666              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2667              ));
2668            } :
2669            function( a, b ) {
2670              if ( b ) {
2671                while ( (b = b.parentNode) ) {
2672                  if ( b === a ) {
2673                    return true;
2674                  }
2675                }
2676              }
2677              return false;
2678            };
2679
2680          events[type] = [];
2681
2682          // Refer to jQuery's implementation of mouseenter & mouseleave
2683          // Read about mouseenter and mouseleave:
2684          // http://www.quirksmode.org/js/events_mouse.html#link8
2685          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2686
2687          onFn(element, eventmap[type], function(event) {
2688            var target = this, related = event.relatedTarget;
2689            // For mousenter/leave call the handler if related is outside the target.
2690            // NB: No relatedTarget if the mouse left/entered the browser window
2691            if ( !related || (related !== target && !contains(target, related)) ){
2692              handle(event, type);
2693            }
2694          });
2695
2696        } else {
2697          addEventListenerFn(element, type, handle);
2698          events[type] = [];
2699        }
2700        eventFns = events[type];
2701      }
2702      eventFns.push(fn);
2703    });
2704  },
2705
2706  off: jqLiteOff,
2707
2708  one: function(element, type, fn) {
2709    element = jqLite(element);
2710
2711    //add the listener twice so that when it is called
2712    //you can remove the original function and still be
2713    //able to call element.off(ev, fn) normally
2714    element.on(type, function onFn() {
2715      element.off(type, fn);
2716      element.off(type, onFn);
2717    });
2718    element.on(type, fn);
2719  },
2720
2721  replaceWith: function(element, replaceNode) {
2722    var index, parent = element.parentNode;
2723    jqLiteDealoc(element);
2724    forEach(new JQLite(replaceNode), function(node){
2725      if (index) {
2726        parent.insertBefore(node, index.nextSibling);
2727      } else {
2728        parent.replaceChild(node, element);
2729      }
2730      index = node;
2731    });
2732  },
2733
2734  children: function(element) {
2735    var children = [];
2736    forEach(element.childNodes, function(element){
2737      if (element.nodeType === 1)
2738        children.push(element);
2739    });
2740    return children;
2741  },
2742
2743  contents: function(element) {
2744    return element.childNodes || [];
2745  },
2746
2747  append: function(element, node) {
2748    forEach(new JQLite(node), function(child){
2749      if (element.nodeType === 1 || element.nodeType === 11) {
2750        element.appendChild(child);
2751      }
2752    });
2753  },
2754
2755  prepend: function(element, node) {
2756    if (element.nodeType === 1) {
2757      var index = element.firstChild;
2758      forEach(new JQLite(node), function(child){
2759        element.insertBefore(child, index);
2760      });
2761    }
2762  },
2763
2764  wrap: function(element, wrapNode) {
2765    wrapNode = jqLite(wrapNode)[0];
2766    var parent = element.parentNode;
2767    if (parent) {
2768      parent.replaceChild(wrapNode, element);
2769    }
2770    wrapNode.appendChild(element);
2771  },
2772
2773  remove: function(element) {
2774    jqLiteDealoc(element);
2775    var parent = element.parentNode;
2776    if (parent) parent.removeChild(element);
2777  },
2778
2779  after: function(element, newElement) {
2780    var index = element, parent = element.parentNode;
2781    forEach(new JQLite(newElement), function(node){
2782      parent.insertBefore(node, index.nextSibling);
2783      index = node;
2784    });
2785  },
2786
2787  addClass: jqLiteAddClass,
2788  removeClass: jqLiteRemoveClass,
2789
2790  toggleClass: function(element, selector, condition) {
2791    if (isUndefined(condition)) {
2792      condition = !jqLiteHasClass(element, selector);
2793    }
2794    (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector);
2795  },
2796
2797  parent: function(element) {
2798    var parent = element.parentNode;
2799    return parent && parent.nodeType !== 11 ? parent : null;
2800  },
2801
2802  next: function(element) {
2803    if (element.nextElementSibling) {
2804      return element.nextElementSibling;
2805    }
2806
2807    // IE8 doesn't have nextElementSibling
2808    var elm = element.nextSibling;
2809    while (elm != null && elm.nodeType !== 1) {
2810      elm = elm.nextSibling;
2811    }
2812    return elm;
2813  },
2814
2815  find: function(element, selector) {
2816    if (element.getElementsByTagName) {
2817      return element.getElementsByTagName(selector);
2818    } else {
2819      return [];
2820    }
2821  },
2822
2823  clone: jqLiteClone,
2824
2825  triggerHandler: function(element, eventName, eventData) {
2826    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
2827
2828    eventData = eventData || [];
2829
2830    var event = [{
2831      preventDefault: noop,
2832      stopPropagation: noop
2833    }];
2834
2835    forEach(eventFns, function(fn) {
2836      fn.apply(element, event.concat(eventData));
2837    });
2838  }
2839}, function(fn, name){
2840  /**
2841   * chaining functions
2842   */
2843  JQLite.prototype[name] = function(arg1, arg2, arg3) {
2844    var value;
2845    for(var i=0; i < this.length; i++) {
2846      if (isUndefined(value)) {
2847        value = fn(this[i], arg1, arg2, arg3);
2848        if (isDefined(value)) {
2849          // any function which returns a value needs to be wrapped
2850          value = jqLite(value);
2851        }
2852      } else {
2853        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
2854      }
2855    }
2856    return isDefined(value) ? value : this;
2857  };
2858
2859  // bind legacy bind/unbind to on/off
2860  JQLite.prototype.bind = JQLite.prototype.on;
2861  JQLite.prototype.unbind = JQLite.prototype.off;
2862});
2863
2864/**
2865 * Computes a hash of an 'obj'.
2866 * Hash of a:
2867 *  string is string
2868 *  number is number as string
2869 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
2870 *         that is also assigned to the $$hashKey property of the object.
2871 *
2872 * @param obj
2873 * @returns {string} hash string such that the same input will have the same hash string.
2874 *         The resulting string key is in 'type:hashKey' format.
2875 */
2876function hashKey(obj) {
2877  var objType = typeof obj,
2878      key;
2879
2880  if (objType == 'object' && obj !== null) {
2881    if (typeof (key = obj.$$hashKey) == 'function') {
2882      // must invoke on object to keep the right this
2883      key = obj.$$hashKey();
2884    } else if (key === undefined) {
2885      key = obj.$$hashKey = nextUid();
2886    }
2887  } else {
2888    key = obj;
2889  }
2890
2891  return objType + ':' + key;
2892}
2893
2894/**
2895 * HashMap which can use objects as keys
2896 */
2897function HashMap(array){
2898  forEach(array, this.put, this);
2899}
2900HashMap.prototype = {
2901  /**
2902   * Store key value pair
2903   * @param key key to store can be any type
2904   * @param value value to store can be any type
2905   */
2906  put: function(key, value) {
2907    this[hashKey(key)] = value;
2908  },
2909
2910  /**
2911   * @param key
2912   * @returns the value for the key
2913   */
2914  get: function(key) {
2915    return this[hashKey(key)];
2916  },
2917
2918  /**
2919   * Remove the key/value pair
2920   * @param key
2921   */
2922  remove: function(key) {
2923    var value = this[key = hashKey(key)];
2924    delete this[key];
2925    return value;
2926  }
2927};
2928
2929/**
2930 * @ngdoc function
2931 * @name angular.injector
2932 * @function
2933 *
2934 * @description
2935 * Creates an injector function that can be used for retrieving services as well as for
2936 * dependency injection (see {@link guide/di dependency injection}).
2937 *
2938
2939 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
2940 *        {@link angular.module}. The `ng` module must be explicitly added.
2941 * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
2942 *
2943 * @example
2944 * Typical usage
2945 * <pre>
2946 *   // create an injector
2947 *   var $injector = angular.injector(['ng']);
2948 *
2949 *   // use the injector to kick off your application
2950 *   // use the type inference to auto inject arguments, or use impl
2950icit injection
2951 *   $injector.invoke(function($rootScope, $compile, $document){
2952 *     $compile($document)($rootScope);
2953 *     $rootScope.$digest();
2954 *   });
2955 * </pre>
2956 *
2957 * Sometimes you want to get access to the injector of a currently running Angular app
2958 * from outside Angular. Perhaps, you want to inject and compile some markup after the
2959 * application has been bootstrapped. You can do this using extra `injector()` added
2960 * to JQuery/jqLite elements. See {@link angular.element}.
2961 *
2962 * *This is fairly rare but could be the case if a third party library is injecting the
2963 * markup.*
2964 *
2965 * In the following example a new block of HTML containing a `ng-controller`
2966 * directive is added to the end of the document body by JQuery. We then compile and link
2967 * it into the current AngularJS scope.
2968 *
2969 * <pre>
2970 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
2971 * $(document.body).append($div);
2972 *
2973 * angular.element(document).injector().invoke(function($compile) {
2974 *   var scope = angular.element($div).scope();
2975 *   $compile($div)(scope);
2976 * });
2977 * </pre>
2978 */
2979
2980
2981/**
2982 * @ngdoc overview
2983 * @name AUTO
2984 * @description
2985 *
2986 * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
2987 */
2988
2989var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
2990var FN_ARG_SPLIT = /,/;
2991var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
2992var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
2993var $injectorMinErr = minErr('$injector');
2994function annotate(fn) {
2995  var $inject,
2996      fnText,
2997      argDecl,
2998      last;
2999
3000  if (typeof fn == 'function') {
3001    if (!($inject = fn.$inject)) {
3002      $inject = [];
3003      if (fn.length) {
3004        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3005        argDecl = fnText.match(FN_ARGS);
3006        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3007          arg.replace(FN_ARG, function(all, underscore, name){
3008            $inject.push(name);
3009          });
3010        });
3011      }
3012      fn.$inject = $inject;
3013    }
3014  } else if (isArray(fn)) {
3015    last = fn.length - 1;
3016    assertArgFn(fn[last], 'fn');
3017    $inject = fn.slice(0, last);
3018  } else {
3019    assertArgFn(fn, 'fn', true);
3020  }
3021  return $inject;
3022}
3023
3024///////////////////////////////////////
3025
3026/**
3027 * @ngdoc object
3028 * @name AUTO.$injector
3029 * @function
3030 *
3031 * @description
3032 *
3033 * `$injector` is used to retrieve object instances as defined by
3034 * {@link AUTO.$provide provider}, instantiate types, invoke methods,
3035 * and load modules.
3036 *
3037 * The following always holds true:
3038 *
3039 * <pre>
3040 *   var $injector = angular.injector();
3041 *   expect($injector.get('$injector')).toBe($injector);
3042 *   expect($injector.invoke(function($injector){
3043 *     return $injector;
3044 *   }).toBe($injector);
3045 * </pre>
3046 *
3047 * # Injection Function Annotation
3048 *
3049 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3050 * following are all valid ways of annotating function with injection arguments and are equivalent.
3051 *
3052 * <pre>
3053 *   // inferred (only works if code not minified/obfuscated)
3054 *   $injector.invoke(function(serviceA){});
3055 *
3056 *   // annotated
3057 *   function explicit(serviceA) {};
3058 *   explicit.$inject = ['serviceA'];
3059 *   $injector.invoke(explicit);
3060 *
3061 *   // inline
3062 *   $injector.invoke(['serviceA', function(serviceA){}]);
3063 * </pre>
3064 *
3065 * ## Inference
3066 *
3067 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3068 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3069 * minification, and obfuscation tools since these tools change the argument names.
3070 *
3071 * ## `$inject` Annotation
3072 * By adding a `$inject` property onto a function the injection parameters can be specified.
3073 *
3074 * ## Inline
3075 * As an array of injection names, where the last item in the array is the function to call.
3076 */
3077
3078/**
3079 * @ngdoc method
3080 * @name AUTO.$injector#get
3081 * @methodOf AUTO.$injector
3082 *
3083 * @description
3084 * Return an instance of the service.
3085 *
3086 * @param {string} name The name of the instance to retrieve.
3087 * @return {*} The instance.
3088 */
3089
3090/**
3091 * @ngdoc method
3092 * @name AUTO.$injector#invoke
3093 * @methodOf AUTO.$injector
3094 *
3095 * @description
3096 * Invoke the method and supply the method arguments from the `$injector`.
3097 *
3098 * @param {!function} fn The function to invoke. Function parameters are injected according to the
3099 *   {@link guide/di $inject Annotation} rules.
3100 * @param {Object=} self The `this` for the invoked method.
3101 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3102 *                         object first, before the `$injector` is consulted.
3103 * @returns {*} the value returned by the invoked `fn` function.
3104 */
3105
3106/**
3107 * @ngdoc method
3108 * @name AUTO.$injector#has
3109 * @methodOf AUTO.$injector
3110 *
3111 * @description
3112 * Allows the user to query if the particular service exist.
3113 *
3114 * @param {string} Name of the service to query.
3115 * @returns {boolean} returns true if injector has given service.
3116 */
3117
3118/**
3119 * @ngdoc method
3120 * @name AUTO.$injector#instantiate
3121 * @methodOf AUTO.$injector
3122 * @description
3123 * Create a new instance of JS type. The method takes a constructor function invokes the new
3124 * operator and supplies all of the arguments to the constructor function as specified by the
3125 * constructor annotation.
3126 *
3127 * @param {function} Type Annotated constructor function.
3128 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3129 * object first, before the `$injector` is consulted.
3130 * @returns {Object} new instance of `Type`.
3131 */
3132
3133/**
3134 * @ngdoc method
3135 * @name AUTO.$injector#annotate
3136 * @methodOf AUTO.$injector
3137 *
3138 * @description
3139 * Returns an array of service names which the function is requesting for injection. This API is
3140 * used by the injector to determine which services need to be injected into the function when the
3141 * function is invoked. There are three ways in which the function can be annotated with the needed
3142 * dependencies.
3143 *
3144 * # Argument names
3145 *
3146 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3147 * by converting the function into a string using `toString()` method and extracting the argument
3148 * names.
3149 * <pre>
3150 *   // Given
3151 *   function MyController($scope, $route) {
3152 *     // ...
3153 *   }
3154 *
3155 *   // Then
3156 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3157 * </pre>
3158 *
3159 * This method does not work with code minification / obfuscation. For this reason the following
3160 * annotation strategies are supported.
3161 *
3162 * # The `$inject` property
3163 *
3164 * If a function has an `$inject` property and its value is an array of strings, then the strings
3165 * represent names of services to be injected into the function.
3166 * <pre>
3167 *   // Given
3168 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3169 *     // ...
3170 *   }
3171 *   // Define function dependencies
3172 *   MyController['$inject'] = ['$scope', '$route'];
3173 *
3174 *   // Then
3175 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3176 * </pre>
3177 *
3178 * # The array notation
3179 *
3180 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3181 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3182 * a way that survives minification is a better choice:
3183 *
3184 * <pre>
3185 *   // We wish to write this (not minification / obfuscation safe)
3186 *   injector.invoke(function($compile, $rootScope) {
3187 *     // ...
3188 *   });
3189 *
3190 *   // We are forced to write break inlining
3191 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3192 *     // ...
3193 *   };
3194 *   tmpFn.$inject = ['$compile', '$rootScope'];
3195 *   injector.invoke(tmpFn);
3196 *
3197 *   // To better support inline function the inline annotation is supported
3198 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3199 *     // ...
3200 *   }]);
3201 *
3202 *   // Therefore
3203 *   expect(injector.annotate(
3204 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3205 *    ).toEqual(['$compile', '$rootScope']);
3206 * </pre>
3207 *
3208 * @param {function|Array.<string|Function>} fn Function for which dependent service names need to
3209 * be retrieved as described above.
3210 *
3211 * @returns {Array.<string>} The names of the services which the function requires.
3212 */
3213
3214
3215
3216
3217/**
3218 * @ngdoc object
3219 * @name AUTO.$provide
3220 *
3221 * @description
3222 *
3223 * The {@link AUTO.$provide $provide} service has a number of methods for registering components
3224 * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on
3225 * {@link angular.Module}.
3226 *
3227 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3228 * factories** are functions which, in turn, are created by a **service provider**.
3229 * The **service providers** are constructor functions. When instantiated they must contain a
3230 * property called `$get`, which holds the **service factory** function.
3231 *
3232 * When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
3233 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3234 * function to get the instance of the **service**.
3235 *
3236 * Often services have no configuration options and there is no need to add methods to the service
3237 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3238 * these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
3239 * services without specifying a provider.
3240 *
3241 * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the
3242 *     {@link AUTO.$injector $injector}
3243 * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by
3244 *     providers and services.
3245 * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by
3246 *     services, not providers.
3247 * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`,
3248 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3249 *     given factory function.
3250 * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that
3251 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3252 *      a new object using the given constructor function.
3253 *
3254 * See the individual methods for more information and examples.
3255 */
3256
3257/**
3258 * @ngdoc method
3259 * @name AUTO.$provide#provider
3260 * @methodOf AUTO.$provide
3261 * @description
3262 *
3263 * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions
3264 * are constructor functions, whose instances are responsible for "providing" a factory for a
3265 * service.
3266 *
3267 * Service provider names start with the name of the service they provide followed by `Provider`.
3268 * For example, the {@link ng.$log $log} service has a provider called
3269 * {@link ng.$logProvider $logProvider}.
3270 *
3271 * Service provider objects can have additional methods which allow configuration of the provider
3272 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3273 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3274 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3275 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3276 * console or not.
3277 *
3278 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3279                        'Provider'` key.
3280 * @param {(Object|function())} provider If the provider is:
3281 *
3282 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3283 *     {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
3284 *   - `Constructor`: a new instance of the provider will be created using                     
3285 *     {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3286 *
3287 * @returns {Object} registered provider instance
3288
3289 * @example
3290 *
3291 * The following example shows how to create a simple event tracking service and register it using
3292 * {@link AUTO.$provide#methods_provider $provide.provider()}.
3293 *
3294 * <pre>
3295 *  // Define the eventTracker provider
3296 *  function EventTrackerProvider() {
3297 *    var trackingUrl = '/track';
3298 *
3299 *    // A provider method for configuring where the tracked events should been saved
3300 *    this.setTrackingUrl = function(url) {
3301 *      trackingUrl = url;
3302 *    };
3303 *
3304 *    // The service factory function
3305 *    this.$get = ['$http', function($http) {
3306 *      var trackedEvents = {};
3307 *      return {
3308 *        // Call this to track an event
3309 *        event: function(event) {
3310 *          var count = trackedEvents[event] || 0;
3311 *          count += 1;
3312 *          trackedEvents[event] = count;
3313 *          return count;
3314 *        },
3315 *        // Call this to save the tracked events to the trackingUrl
3316 *        save: function() {
3317 *          $http.post(trackingUrl, trackedEvents);
3318 *        }
3319 *      };
3320 *    }];
3321 *  }
3322 *
3323 *  describe('eventTracker', function() {
3324 *    var postSpy;
3325 *
3326 *    beforeEach(module(function($provide) {
3327 *      // Register the eventTracker provider
3328 *      $provide.provider('eventTracker', EventTrackerProvider);
3329 *    }));
3330 *
3331 *    beforeEach(module(function(eventTrackerProvider) {
3332 *      // Configure eventTracker provider
3333 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3334 *    }));
3335 *
3336 *    it('tracks events', inject(function(eventTracker) {
3337 *      expect(eventTracker.event('login')).toEqual(1);
3338 *      expect(eventTracker.event('login')).toEqual(2);
3339 *    }));
3340 *
3341 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3342 *      postSpy = spyOn($http, 'post');
3343 *      eventTracker.event('login');
3344 *      eventTracker.save();
3345 *      expect(postSpy).toHaveBeenCalled();
3346 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3347 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3348 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3349 *    }));
3350 *  });
3351 * </pre>
3352 */
3353
3354/**
3355 * @ngdoc method
3356 * @name AUTO.$provide#factory
3357 * @methodOf AUTO.$provide
3358 * @description
3359 *
3360 * Register a **service factory**, which will be called to return the service instance.
3361 * This is short for registering a service where its provider consists of only a `$get` property,
3362 * which is the given service factory function.
3363 * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to
3364 * configure your service in a provider.
3365 *
3366 * @param {string} name The name of the instance.
3367 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3368 *                            for `$provide.provider(name, {$get: $getFn})`.
3369 * @returns {Object} registered provider instance
3370 *
3371 * @example
3372 * Here is an example of registering a service
3373 * <pre>
3374 *   $provide.factory('ping', ['$http', function($http) {
3375 *     return function ping() {
3376 *       return $http.send('/ping');
3377 *     };
3378 *   }]);
3379 * </pre>
3380 * You would then inject and use this service like this:
3381 * <pre>
3382 *   someModule.controller('Ctrl', ['ping', function(ping) {
3383 *     ping();
3384 *   }]);
3385 * </pre>
3386 */
3387
3388
3389/**
3390 * @ngdoc method
3391 * @name AUTO.$provide#service
3392 * @methodOf AUTO.$provide
3393 * @description
3394 *
3395 * Register a **service constructor**, which will be invoked with `new` to create the service
3396 * instance.
3397 * This is short for registering a service where its provider's `$get` property is the service
3398 * constructor function that will be used to instantiate the service instance.
3399 *
3400 * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
3401 * as a type/class.
3402 *
3403 * @param {string} name The name of the instance.
3404 * @param {Function} constructor A class (constructor function) that will be instantiated.
3405 * @returns {Object} registered provider instance
3406 *
3407 * @example
3408 * Here is an example of registering a service using
3409 * {@link AUTO.$provide#methods_service $provide.service(class)}.
3410 * <pre>
3411 *   $provide.service('ping', ['$http', function($http) {
3412 *     var Ping = function() {
3413 *       this.$http = $http;
3414 *     };
3415 *   
3416 *     Ping.prototype.send = function() {
3417 *       return this.$http.get('/ping');
3418 *     }; 
3419 *   
3420 *     return Ping;
3421 *   }]);
3422 * </pre>
3423 * You would then inject and use this service like this:
3424 * <pre>
3425 *   someModule.controller('Ctrl', ['ping', function(ping) {
3426 *     ping.send();
3427 *   }]);
3428 * </pre>
3429 */
3430
3431
3432/**
3433 * @ngdoc method
3434 * @name AUTO.$provide#value
3435 * @methodOf AUTO.$provide
3436 * @description
3437 *
3438 * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a
3439 * number, an array, an object or a function.  This is short for registering a service where its
3440 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3441 * service**.
3442 *
3443 * Value services are similar to constant services, except that they cannot be injected into a
3444 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3445 * an Angular
3446 * {@link AUTO.$provide#decorator decorator}.
3447 *
3448 * @param {string} name The name of the instance.
3449 * @param {*} value The value.
3450 * @returns {Object} registered provider instance
3451 *
3452 * @example
3453 * Here are some examples of creating value services.
3454 * <pre>
3455 *   $provide.value('ADMIN_USER', 'admin');
3456 *
3457 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3458 *
3459 *   $provide.value('halfOf', function(value) {
3460 *     return value / 2;
3461 *   });
3462 * </pre>
3463 */
3464
3465
3466/**
3467 * @ngdoc method
3468 * @name AUTO.$provide#constant
3469 * @methodOf AUTO.$provide
3470 * @description
3471 *
3472 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3473 * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be
3474 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3475 * be overridden by an Angular {@link AUTO.$provide#decorator decorator}.
3476 *
3477 * @param {string} name The name of the constant.
3478 * @param {*} value The constant value.
3479 * @returns {Object} registered instance
3480 *
3481 * @example
3482 * Here a some examples of creating constants:
3483 * <pre>
3484 *   $provide.constant('SHARD_HEIGHT', 306);
3485 *
3486 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3487 *
3488 *   $provide.constant('double', function(value) {
3489 *     return value * 2;
3490 *   });
3491 * </pre>
3492 */
3493
3494
3495/**
3496 * @ngdoc method
3497 * @name AUTO.$provide#decorator
3498 * @methodOf AUTO.$provide
3499 * @description
3500 *
3501 * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator
3502 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3503 * service. The object returned by the decorator may be the original service, or a new service
3504 * object which replaces or wraps and delegates to the original service.
3505 *
3506 * @param {string} name The name of the service to decorate.
3507 * @param {function()} decorator This function will be invoked when the service needs to be
3508 *    instantiated and should return the decorated service instance. The function is called using
3509 *    the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
3510 *    Local injection arguments:
3511 *
3512 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3513 *      decorated or delegated to.
3514 *
3515 * @example
3516 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3517 * calls to {@link ng.$log#error $log.warn()}.
3518 * <pre>
3519 *   $provider.decorator('$log', ['$delegate', function($delegate) {
3520 *     $delegate.warn = $delegate.error;
3521 *     return $delegate;
3522 *   }]);
3523 * </pre>
3524 */
3525
3526
3527function createInjector(modulesToLoad) {
3528  var INSTANTIATING = {},
3529      providerSuffix = 'Provider',
3530      path = [],
3531      loadedModules = new HashMap(),
3532      providerCache = {
3533        $provide: {
3534            provider: supportObject(provider),
3535            factory: supportObject(factory),
3536            service: supportObject(service),
3537            value: supportObject(value),
3538            constant: supportObject(constant),
3539            decorator: decorator
3540          }
3541      },
3542      providerInjector = (providerCache.$injector =
3543          createInternalInjector(providerCache, function() {
3544            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3545          })),
3546      instanceCache = {},
3547      instanceInjector = (instanceCache.$injector =
3548          createInternalInjector(instanceCache, function(servicename) {
3549            var provider = providerInjector.get(servicename + providerSuffix);
3550            return instanceInjector.invoke(provider.$get, provider);
3551          }));
3552
3553
3554  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3555
3556  return instanceInjector;
3557
3558  ////////////////////////////////////
3559  // $provider
3560  ////////////////////////////////////
3561
3562  function supportObject(delegate) {
3563    return function(key, value) {
3564      if (isObject(key)) {
3565        forEach(key, reverseParams(delegate));
3566      } else {
3567        return delegate(key, value);
3568      }
3569    };
3570  }
3571
3572  function provider(name, provider_) {
3573    assertNotHasOwnProperty(name, 'service');
3574    if (isFunction(provider_) || isArray(provider_)) {
3575      provider_ = providerInjector.instantiate(provider_);
3576    }
3577    if (!provider_.$get) {
3578      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3579    }
3580    return providerCache[name + providerSuffix] = provider_;
3581  }
3582
3583  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3584
3585  function service(name, constructor) {
3586    return factory(name, ['$injector', function($injector) {
3587      return $injector.instantiate(constructor);
3588    }]);
3589  }
3590
3591  function value(name, val) { return factory(name, valueFn(val)); }
3592
3593  function constant(name, value) {
3594    assertNotHasOwnProperty(name, 'constant');
3595    providerCache[name] = value;
3596    instanceCache[name] = value;
3597  }
3598
3599  function decorator(serviceName, decorFn) {
3600    var origProvider = providerInjector.get(serviceName + providerSuffix),
3601        orig$get = origProvider.$get;
3602
3603    origProvider.$get = function() {
3604      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3605      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3606    };
3607  }
3608
3609  ////////////////////////////////////
3610  // Module Loading
3611  ////////////////////////////////////
3612  function loadModules(modulesToLoad){
3613    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3614    forEach(modulesToLoad, function(module) {
3615      if (loadedModules.get(module)) return;
3616      loadedModules.put(module, true);
3617
3618      try {
3619        if (isString(module)) {
3620          moduleFn = angularModule(module);
3621          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3622
3623          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3624            var invokeArgs = invokeQueue[i],
3625                provider = providerInjector.get(invokeArgs[0]);
3626
3627            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3628          }
3629        } else if (isFunction(module)) {
3630            runBlocks.push(providerInjector.invoke(module));
3631        } else if (isArray(module)) {
3632            runBlocks.push(providerInjector.invoke(module));
3633        } else {
3634          assertArgFn(module, 'module');
3635        }
3636      } catch (e) {
3637        if (isArray(module)) {
3638          module = module[module.length - 1];
3639        }
3640        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3641          // Safari & FF's stack traces don't contain error.message content
3642          // unlike those of Chrome and IE
3643          // So if stack doesn't contain message, we create a new string that contains both.
3644          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3645          /* jshint -W022 */
3646          e = e.message + '\n' + e.stack;
3647        }
3648        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3649                  module, e.stack || e.message || e);
3650      }
3651    });
3652    return runBlocks;
3653  }
3654
3655  ////////////////////////////////////
3656  // internal Injector
3657  ////////////////////////////////////
3658
3659  function createInternalInjector(cache, factory) {
3660
3661    function getService(serviceName) {
3662      if (cache.hasOwnProperty(serviceName)) {
3663        if (cache[serviceName] === INSTANTIATING) {
3664          throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
3665        }
3666        return cache[serviceName];
3667      } else {
3668        try {
3669          path.unshift(serviceName);
3670          cache[serviceName] = INSTANTIATING;
3671          return cache[serviceName] = factory(serviceName);
3672        } catch (err) {
3673          if (cache[serviceName] === INSTANTIATING) {
3674            delete cache[serviceName];
3675          }
3676          throw err;
3677        } finally {
3678          path.shift();
3679        }
3680      }
3681    }
3682
3683    function invoke(fn, self, locals){
3684      var args = [],
3685          $inject = annotate(fn),
3686          length, i,
3687          key;
3688
3689      for(i = 0, length = $inject.length; i < length; i++) {
3690        key = $inject[i];
3691        if (typeof key !== 'string') {
3692          throw $injectorMinErr('itkn',
3693                  'Incorrect injection token! Expected service name as string, got {0}', key);
3694        }
3695        args.push(
3696          locals && locals.hasOwnProperty(key)
3697          ? locals[key]
3698          : getService(key)
3699        );
3700      }
3701      if (!fn.$inject) {
3702        // this means that we must be an array.
3703        fn = fn[length];
3704      }
3705
3706      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3707      // #5388
3708      return fn.apply(self, args);
3709    }
3710
3711    function instantiate(Type, locals) {
3712      var Constructor = function() {},
3713          instance, returnedValue;
3714
3715      // Check if Type is annotated and use just the given function at n-1 as parameter
3716      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3717      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3718      instance = new Constructor();
3719      returnedValue = invoke(Type, instance, locals);
3720
3721      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3722    }
3723
3724    return {
3725      invoke: invoke,
3726      instantiate: instantiate,
3727      get: getService,
3728      annotate: annotate,
3729      has: function(name) {
3730        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3731      }
3732    };
3733  }
3734}
3735
3736/**
3737 * @ngdoc function
3738 * @name ng.$anchorScroll
3739 * @requires $window
3740 * @requires $location
3741 * @requires $rootScope
3742 *
3743 * @description
3744 * When called, it checks current value of `$location.hash()` and scroll to related element,
3745 * according to rules specified in
3746 * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
3747 *
3748 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3749 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3750 * 
3751 * @example
3752   <example>
3753     <file name="index.html">
3754       <div id="scrollArea" ng-controller="ScrollCtrl">
3755         <a ng-click="gotoBottom()">Go to bottom</a>
3756         <a id="bottom"></a> You're at the bottom!
3757       </div>
3758     </file>
3759     <file name="script.js">
3760       function ScrollCtrl($scope, $location, $anchorScroll) {
3761         $scope.gotoBottom = function (){
3762           // set the location.hash to the id of
3763           // the element you wish to scroll to.
3764           $location.hash('bottom');
3765           
3766           // call $anchorScroll()
3767           $anchorScroll();
3768         }
3769       }
3770     </file>
3771     <file name="style.css">
3772       #scrollArea {
3773         height: 350px;
3774         overflow: auto;
3775       }
3776
3777       #bottom {
3778         display: block;
3779         margin-top: 2000px;
3780       }
3781     </file>
3782   </example>
3783 */
3784function $AnchorScrollProvider() {
3785
3786  var autoScrollingEnabled = true;
3787
3788  this.disableAutoScrolling = function() {
3789    autoScrollingEnabled = false;
3790  };
3791
3792  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
3793    var document = $window.document;
3794
3795    // helper function to get first anchor from a NodeList
3796    // can't use filter.filter, as it accepts only instances of Array
3797    // and IE can't convert NodeList to an array using [].slice
3798    // TODO(vojta): use filter if we change it to accept lists as well
3799    function getFirstAnchor(list) {
3800      var result = null;
3801      forEach(list, function(element) {
3802        if (!result && lowercase(element.nodeName) === 'a') result = element;
3803      });
3804      return result;
3805    }
3806
3807    function scroll() {
3808      var hash = $location.hash(), elm;
3809
3810      // empty hash, scroll to the top of the page
3811      if (!hash) $window.scrollTo(0, 0);
3812
3813      // element with given id
3814      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
3815
3816      // first anchor with given name :-D
3817      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
3818
3819      // no element and hash == 'top', scroll to the top of the page
3820      else if (hash === 'top') $window.scrollTo(0, 0);
3821    }
3822
3823    // does not scroll when user clicks on anchor link that is currently on
3824    // (no url change, no $location.hash() change), browser native does scroll
3825    if (autoScrollingEnabled) {
3826      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
3827        function autoScrollWatchAction() {
3828          $rootScope.$evalAsync(scroll);
3829        });
3830    }
3831
3832    return scroll;
3833  }];
3834}
3835
3836var $animateMinErr = minErr('$animate');
3837
3838/**
3839 * @ngdoc object
3840 * @name ng.$animateProvider
3841 *
3842 * @description
3843 * Default implementation of $animate that doesn't perform any animations, instead just
3844 * synchronously performs DOM
3845 * updates and calls done() callbacks.
3846 *
3847 * In order to enable animations the ngAnimate module has to be loaded.
3848 *
3849 * To see the functional implementation check out src/ngAnimate/animate.js
3850 */
3851var $AnimateProvider = ['$provide', function($provide) {
3852
3853  
3854  this.$$selectors = {};
3855
3856
3857  /**
3858   * @ngdoc function
3859   * @name ng.$animateProvider#register
3860   * @methodOf ng.$animateProvider
3861   *
3862   * @description
3863   * Registers a new injectable animation factory function. The factory function produces the
3864   * animation object which contains callback functions for each event that is expected to be
3865   * animated.
3866   *
3867   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
3868   *   must be called once the element animation is complete. If a function is returned then the
3869   *   animation service will use this function to cancel the animation whenever a cancel event is
3870   *   triggered.
3871   *
3872   *
3873   *<pre>
3874   *   return {
3875     *     eventFn : function(element, done) {
3876     *       //code to run the animation
3877     *       //once complete, then run done()
3878     *       return function cancellationFunction() {
3879     *         //code to cancel the animation
3880     *       }
3881     *     }
3882     *   }
3883   *</pre>
3884   *
3885   * @param {string} name The name of the animation.
3886   * @param {function} factory The factory function that will be executed to return the animation
3887   *                           object.
3888   */
3889  this.register = function(name, factory) {
3890    var key = name + '-animation';
3891    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
3892        "Expecting class selector starting with '.' got '{0}'.", name);
3893    this.$$selectors[name.substr(1)] = key;
3894    $provide.factory(key, factory);
3895  };
3896
3897  /**
3898   * @ngdoc function
3899   * @name ng.$animateProvider#classNameFilter
3900   * @methodOf ng.$animateProvider
3901   *
3902   * @description
3903   * Sets and/or returns the CSS class regular expression that is checked when performing
3904   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
3905   * therefore enable $animate to attempt to perform an animation on any element.
3906   * When setting the classNameFilter value, animations will only be performed on elements
3907   * that successfully match the filter expression. This in turn can boost performance
3908   * for low-powered devices as well as applications containing a lot of structural operations.
3909   * @param {RegExp=} expression The className expression which will be checked against all animations
3910   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
3911   */
3912  this.classNameFilter = function(expression) {
3913    if(arguments.length === 1) {
3914      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
3915    }
3916    return this.$$classNameFilter;
3917  };
3918
3919  this.$get = ['$timeout', function($timeout) {
3920
3921    /**
3922     *
3923     * @ngdoc object
3924     * @name ng.$animate
3925     * @description The $animate service provides rudimentary DOM manipulation functions to
3926     * insert, remove and move elements within the DOM, as well as adding and removing classes.
3927     * This service is the core service used by the ngAnimate $animator service which provides
3928     * high-level animation hooks for CSS and JavaScript.
3929     *
3930     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
3931     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
3932     * manipulation operations.
3933     *
3934     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
3935     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
3936     * page}.
3937     */
3938    return {
3939
3940      /**
3941       *
3942       * @ngdoc function
3943       * @name ng.$animate#enter
3944       * @methodOf ng.$animate
3945       * @function
3946       * @description Inserts the element into the DOM either after the `after` element or within
3947       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
3948       * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
3949       * @param {jQuery/jqLite element} parent the parent element which will append the element as
3950       *   a child (if the after element is not present)
3951       * @param {jQuery/jqLite element} after the sibling element which will append the element
3952       *   after itself
3953       * @param {function=} done callback function that will be called after the element has been
3954       *   inserted into the DOM
3955       */
3956      enter : function(element, parent, after, done) {
3957        if (after) {
3958          after.after(element);
3959        } else {
3960          if (!parent || !parent[0]) {
3961            parent = after.parent();
3962          }
3963          parent.append(element);
3964        }
3965        done && $timeout(done, 0, false);
3966      },
3967
3968      /**
3969       *
3970       * @ngdoc function
3971       * @name ng.$animate#leave
3972       * @methodOf ng.$animate
3973       * @function
3974       * @description Removes the element from the DOM. Once complete, the done() callback will be
3975       *   fired (if provided).
3976       * @param {jQuery/jqLite element} element the element which will be removed from the DOM
3977       * @param {function=} done callback function that will be called after the element has been
3978       *   removed from the DOM
3979       */
3980      leave : function(element, done) {
3981        element.remove();
3982        done && $timeout(done, 0, false);
3983      },
3984
3985      /**
3986       *
3987       * @ngdoc function
3988       * @name ng.$animate#move
3989       * @methodOf ng.$animate
3990       * @function
3991       * @description Moves the position of the provided element within the DOM to be placed
3992       * either after the `after` element or inside of the `parent` element. Once complete, the
3993       * done() callback will be fired (if provided).
3994       * 
3995       * @param {jQuery/jqLite element} element the element which will be moved around within the
3996       *   DOM
3997       * @param {jQuery/jqLite element} parent the parent element where the element will be
3998       *   inserted into (if the after element is not present)
3999       * @param {jQuery/jqLite element} after the sibling element where the element will be
4000       *   positioned next to
4001       * @param {function=} done the callback function (if provided) that will be fired after the
4002       *   element has been moved to its new position
4003       */
4004      move : function(element, parent, after, done) {
4005        // Do not remove element before insert. Removing will cause data associated with the
4006        // element to be dropped. Insert will implicitly do the remove.
4007        this.enter(element, parent, after, done);
4008      },
4009
4010      /**
4011       *
4012       * @ngdoc function
4013       * @name ng.$animate#addClass
4014       * @methodOf ng.$animate
4015       * @function
4016       * @description Adds the provided className CSS class value to the provided element. Once
4017       * complete, the done() callback will be fired (if provided).
4018       * @param {jQuery/jqLite element} element the element which will have the className value
4019       *   added to it
4020       * @param {string} className the CSS class which will be added to the element
4021       * @param {function=} done the callback function (if provided) that will be fired after the
4022       *   className value has been added to the element
4023       */
4024      addClass : function(element, className, done) {
4025        className = isString(className) ?
4026                      className :
4027                      isArray(className) ? className.join(' ') : '';
4028        forEach(element, function (element) {
4029          jqLiteAddClass(element, className);
4030        });
4031        done && $timeout(done, 0, false);
4032      },
4033
4034      /**
4035       *
4036       * @ngdoc function
4037       * @name ng.$animate#removeClass
4038       * @methodOf ng.$animate
4039       * @function
4040       * @description Removes the provided className CSS class value from the provided element.
4041       * Once complete, the done() callback will be fired (if provided).
4042       * @param {jQuery/jqLite element} element the element which will have the className value
4043       *   removed from it
4044       * @param {string} className the CSS class which will be removed from the element
4045       * @param {function=} done the callback function (if provided) that will be fired after the
4046       *   className value has been removed from the element
4047       */
4048      removeClass : function(element, className, done) {
4049        className = isString(className) ?
4050                      className :
4051                      isArray(className) ? className.join(' ') : '';
4052        forEach(element, function (element) {
4053          jqLiteRemoveClass(element, className);
4054        });
4055        done && $timeout(done, 0, false);
4056      },
4057
4058      enabled : noop
4059    };
4060  }];
4061}];
4062
4063/**
4064 * ! This is a private undocumented service !
4065 *
4066 * @name ng.$browser
4067 * @requires $log
4068 * @description
4069 * This object has two goals:
4070 *
4071 * - hide all the global state in the browser caused by the window object
4072 * - abstract away all the browser specific features and inconsistencies
4073 *
4074 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4075 * service, which can be used for convenient testing of the application without the interaction with
4076 * the real browser apis.
4077 */
4078/**
4079 * @param {object} window The global window object.
4080 * @param {object} document jQuery wrapped document.
4081 * @param {function()} XHR XMLHttpRequest constructor.
4082 * @param {object} $log console.log or an object with the same interface.
4083 * @param {object} $sniffer $sniffer service
4084 */
4085function Browser(window, document, $log, $sniffer) {
4086  var self = this,
4087      rawDocument = document[0],
4088      location = window.location,
4089      history = window.history,
4090      setTimeout = window.setTimeout,
4091      clearTimeout = window.clearTimeout,
4092      pendingDeferIds = {};
4093
4094  self.isMock = false;
4095
4096  var outstandingRequestCount = 0;
4097  var outstandingRequestCallbacks = [];
4098
4099  // TODO(vojta): remove this temporary api
4100  self.$$completeOutstandingRequest = completeOutstandingRequest;
4101  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4102
4103  /**
4104   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4105   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4106   */
4107  function completeOutstandingRequest(fn) {
4108    try {
4109      fn.apply(null, sliceArgs(arguments, 1));
4110    } finally {
4111      outstandingRequestCount--;
4112      if (outstandingRequestCount === 0) {
4113        while(outstandingRequestCallbacks.length) {
4114          try {
4115            outstandingRequestCallbacks.pop()();
4116          } catch (e) {
4117            $log.error(e);
4118          }
4119        }
4120      }
4121    }
4122  }
4123
4124  /**
4125   * @private
4126   * Note: this method is used only by scenario runner
4127   * TODO(vojta): prefix this method with $$ ?
4128   * @param {function()} callback Function that will be called when no outstanding request
4129   */
4130  self.notifyWhenNoOutstandingRequests = function(callback) {
4131    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4132    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4133    // regular poller would result in flaky tests.
4134    forEach(pollFns, function(pollFn){ pollFn(); });
4135
4136    if (outstandingRequestCount === 0) {
4137      callback();
4138    } else {
4139      outstandingRequestCallbacks.push(callback);
4140    }
4141  };
4142
4143  //////////////////////////////////////////////////////////////
4144  // Poll Watcher API
4145  //////////////////////////////////////////////////////////////
4146  var pollFns = [],
4147      pollTimeout;
4148
4149  /**
4150   * @name ng.$browser#addPollFn
4151   * @methodOf ng.$browser
4152   *
4153   * @param {function()} fn Poll function to add
4154   *
4155   * @description
4156   * Adds a function to the list of functions that poller periodically executes,
4157   * and starts polling if not started yet.
4158   *
4159   * @returns {function()} the added function
4160   */
4161  self.addPollFn = function(fn) {
4162    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4163    pollFns.push(fn);
4164    return fn;
4165  };
4166
4167  /**
4168   * @param {number} interval How often should browser call poll functions (ms)
4169   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4170   *
4171   * @description
4172   * Configures the poller to run in the specified intervals, using the specified
4173   * setTimeout fn and kicks it off.
4174   */
4175  function startPoller(interval, setTimeout) {
4176    (function check() {
4177      forEach(pollFns, function(pollFn){ pollFn(); });
4178      pollTimeout = setTimeout(check, interval);
4179    })();
4180  }
4181
4182  //////////////////////////////////////////////////////////////
4183  // URL API
4184  //////////////////////////////////////////////////////////////
4185
4186  var lastBrowserUrl = location.href,
4187      baseElement = document.find('base'),
4188      newLocation = null;
4189
4190  /**
4191   * @name ng.$browser#url
4192   * @methodOf ng.$browser
4193   *
4194   * @description
4195   * GETTER:
4196   * Without any argument, this method just returns current value of location.href.
4197   *
4198   * SETTER:
4199   * With at least one argument, this method sets url to new value.
4200   * If html5 history api supported, pushState/replaceState is used, otherwise
4201   * location.href/location.replace is used.
4202   * Returns its own instance to allow chaining
4203   *
4204   * NOTE: this api is intended for use only by the $location service. Please use the
4205   * {@link ng.$location $location service} to change url.
4206   *
4207   * @param {string} url New url (when used as setter)
4208   * @param {boolean=} replace Should new url replace current history record ?
4209   */
4210  self.url = function(url, replace) {
4211    // Android Browser BFCache causes location, history reference to become stale.
4212    if (location !== window.location) location = window.location;
4213    if (history !== window.history) history = window.history;
4214
4215    // setter
4216    if (url) {
4217      if (lastBrowserUrl == url) return;
4218      lastBrowserUrl = url;
4219      if ($sniffer.history) {
4220        if (replace) history.replaceState(null, '', url);
4221        else {
4222          history.pushState(null, '', url);
4223          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4224          baseElement.attr('href', baseElement.attr('href'));
4225        }
4226      } else {
4227        newLocation = url;
4228        if (replace) {
4229          location.replace(url);
4230        } else {
4231          location.href = url;
4232        }
4233      }
4234      return self;
4235    // getter
4236    } else {
4237      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4238      //   methods not updating location.href synchronously.
4239      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4240      return newLocation || location.href.replace(/%27/g,"'");
4241    }
4242  };
4243
4244  var urlChangeListeners = [],
4245      urlChangeInit = false;
4246
4247  function fireUrlChange() {
4248    newLocation = null;
4249    if (lastBrowserUrl == self.url()) return;
4250
4251    lastBrowserUrl = self.url();
4252    forEach(urlChangeListeners, function(listener) {
4253      listener(self.url());
4254    });
4255  }
4256
4257  /**
4258   * @name ng.$browser#onUrlChange
4259   * @methodOf ng.$browser
4260   * @TODO(vojta): refactor to use node's syntax for events
4261   *
4262   * @description
4263   * Register callback function that will be called, when url changes.
4264   *
4265   * It's only called when the url is changed from outside of angular:
4266   * - user types different url into address bar
4267   * - user clicks on history (forward/back) button
4268   * - user clicks on a link
4269   *
4270   * It's not called when url is changed by $browser.url() method
4271   *
4272   * The listener gets called with new url as parameter.
4273   *
4274   * NOTE: this api is intended for use only by the $location service. Please use the
4275   * {@link ng.$location $location service} to monitor url changes in angular apps.
4276   *
4277   * @param {function(string)} listener Listener function to be called when url changes.
4278   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4279   */
4280  self.onUrlChange = function(callback) {
4281    if (!urlChangeInit) {
4282      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4283      // don't fire popstate when user change the address bar and don't fire hashchange when url
4284      // changed by push/replaceState
4285
4286      // html5 history api - popstate event
4287      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4288      // hashchange event
4289      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4290      // polling
4291      else self.addPollFn(fireUrlChange);
4292
4293      urlChangeInit = true;
4294    }
4295
4296    urlChangeListeners.push(callback);
4297    return callback;
4298  };
4299
4300  //////////////////////////////////////////////////////////////
4301  // Misc API
4302  //////////////////////////////////////////////////////////////
4303
4304  /**
4305   * @name ng.$browser#baseHref
4306   * @methodOf ng.$browser
4307   *
4308   * @description
4309   * Returns current <base href>
4310   * (always relative - without domain)
4311   *
4312   * @returns {string=} current <base href>
4313   */
4314  self.baseHref = function() {
4315    var href = baseElement.attr('href');
4316    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4317  };
4318
4319  //////////////////////////////////////////////////////////////
4320  // Cookies API
4321  //////////////////////////////////////////////////////////////
4322  var lastCookies = {};
4323  var lastCookieString = '';
4324  var cookiePath = self.baseHref();
4325
4326  /**
4327   * @name ng.$browser#cookies
4328   * @methodOf ng.$browser
4329   *
4330   * @param {string=} name Cookie name
4331   * @param {string=} value Cookie value
4332   *
4333   * @description
4334   * The cookies method provides a 'private' low level access to browser cookies.
4335   * It is not meant to be used directly, use the $cookie service instead.
4336   *
4337   * The return values vary depending on the arguments that the method was called with as follows:
4338   *
4339   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4340   *   it
4341   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4342   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4343   *   way)
4344   *
4345   * @returns {Object} Hash of all cookies (if called without any parameter)
4346   */
4347  self.cookies = function(name, value) {
4348    /* global escape: false, unescape: false */
4349    var cookieLength, cookieArray, cookie, i, index;
4350
4351    if (name) {
4352      if (value === undefined) {
4353        rawDocument.cookie = escape(name) + "=;
4353path=" + cookiePath +
4354                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4355      } else {
4356        if (isString(value)) {
4357          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4358                                ';path=' + cookiePath).length + 1;
4359
4360          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4361          // - 300 cookies
4362          // - 20 cookies per unique domain
4363          // - 4096 bytes per cookie
4364          if (cookieLength > 4096) {
4365            $log.warn("Cookie '"+ name +
4366              "' possibly not set or overflowed because it was too large ("+
4367              cookieLength + " > 4096 bytes)!");
4368          }
4369        }
4370      }
4371    } else {
4372      if (rawDocument.cookie !== lastCookieString) {
4373        lastCookieString = rawDocument.cookie;
4374        cookieArray = lastCookieString.split("; ");
4375        lastCookies = {};
4376
4377        for (i = 0; i < cookieArray.length; i++) {
4378          cookie = cookieArray[i];
4379          index = cookie.indexOf('=');
4380          if (index > 0) { //ignore nameless cookies
4381            name = unescape(cookie.substring(0, index));
4382            // the first value that is seen for a cookie is the most
4383            // specific one.  values for the same cookie name that
4384            // follow are for less specific paths.
4385            if (lastCookies[name] === undefined) {
4386              lastCookies[name] = unescape(cookie.substring(index + 1));
4387            }
4388          }
4389        }
4390      }
4391      return lastCookies;
4392    }
4393  };
4394
4395
4396  /**
4397   * @name ng.$browser#defer
4398   * @methodOf ng.$browser
4399   * @param {function()} fn A function, who's execution should be deferred.
4400   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4401   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4402   *
4403   * @description
4404   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4405   *
4406   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4407   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4408   * via `$browser.defer.flush()`.
4409   *
4410   */
4411  self.defer = function(fn, delay) {
4412    var timeoutId;
4413    outstandingRequestCount++;
4414    timeoutId = setTimeout(function() {
4415      delete pendingDeferIds[timeoutId];
4416      completeOutstandingRequest(fn);
4417    }, delay || 0);
4418    pendingDeferIds[timeoutId] = true;
4419    return timeoutId;
4420  };
4421
4422
4423  /**
4424   * @name ng.$browser#defer.cancel
4425   * @methodOf ng.$browser.defer
4426   *
4427   * @description
4428   * Cancels a deferred task identified with `deferId`.
4429   *
4430   * @param {*} deferId Token returned by the `$browser.defer` function.
4431   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4432   *                    canceled.
4433   */
4434  self.defer.cancel = function(deferId) {
4435    if (pendingDeferIds[deferId]) {
4436      delete pendingDeferIds[deferId];
4437      clearTimeout(deferId);
4438      completeOutstandingRequest(noop);
4439      return true;
4440    }
4441    return false;
4442  };
4443
4444}
4445
4446function $BrowserProvider(){
4447  this.$get = ['$window', '$log', '$sniffer', '$document',
4448      function( $window,   $log,   $sniffer,   $document){
4449        return new Browser($window, $document, $log, $sniffer);
4450      }];
4451}
4452
4453/**
4454 * @ngdoc object
4455 * @name ng.$cacheFactory
4456 *
4457 * @description
4458 * Factory that constructs cache objects and gives access to them.
4459 * 
4460 * <pre>
4461 * 
4462 *  var cache = $cacheFactory('cacheId');
4463 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4464 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4465 *
4466 *  cache.put("key", "value");
4467 *  cache.put("another key", "another value");
4468 *
4469 *  // We've specified no options on creation
4470 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2}); 
4471 * 
4472 * </pre>
4473 *
4474 *
4475 * @param {string} cacheId Name or id of the newly created cache.
4476 * @param {object=} options Options object that specifies the cache behavior. Properties:
4477 *
4478 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4479 *
4480 * @returns {object} Newly created cache object with the following set of methods:
4481 *
4482 * - `{object}` `info()` — Returns id, size, and options of cache.
4483 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4484 *   it.
4485 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4486 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4487 * - `{void}` `removeAll()` — Removes all cached values.
4488 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4489 *
4490 */
4491function $CacheFactoryProvider() {
4492
4493  this.$get = function() {
4494    var caches = {};
4495
4496    function cacheFactory(cacheId, options) {
4497      if (cacheId in caches) {
4498        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4499      }
4500
4501      var size = 0,
4502          stats = extend({}, options, {id: cacheId}),
4503          data = {},
4504          capacity = (options && options.capacity) || Number.MAX_VALUE,
4505          lruHash = {},
4506          freshEnd = null,
4507          staleEnd = null;
4508
4509      return caches[cacheId] = {
4510
4511        put: function(key, value) {
4512          var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4513
4514          refresh(lruEntry);
4515
4516          if (isUndefined(value)) return;
4517          if (!(key in data)) size++;
4518          data[key] = value;
4519
4520          if (size > capacity) {
4521            this.remove(staleEnd.key);
4522          }
4523
4524          return value;
4525        },
4526
4527
4528        get: function(key) {
4529          var lruEntry = lruHash[key];
4530
4531          if (!lruEntry) return;
4532
4533          refresh(lruEntry);
4534
4535          return data[key];
4536        },
4537
4538
4539        remove: function(key) {
4540          var lruEntry = lruHash[key];
4541
4542          if (!lruEntry) return;
4543
4544          if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4545          if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4546          link(lruEntry.n,lruEntry.p);
4547
4548          delete lruHash[key];
4549          delete data[key];
4550          size--;
4551        },
4552
4553
4554        removeAll: function() {
4555          data = {};
4556          size = 0;
4557          lruHash = {};
4558          freshEnd = staleEnd = null;
4559        },
4560
4561
4562        destroy: function() {
4563          data = null;
4564          stats = null;
4565          lruHash = null;
4566          delete caches[cacheId];
4567        },
4568
4569
4570        info: function() {
4571          return extend({}, stats, {size: size});
4572        }
4573      };
4574
4575
4576      /**
4577       * makes the `entry` the freshEnd of the LRU linked list
4578       */
4579      function refresh(entry) {
4580        if (entry != freshEnd) {
4581          if (!staleEnd) {
4582            staleEnd = entry;
4583          } else if (staleEnd == entry) {
4584            staleEnd = entry.n;
4585          }
4586
4587          link(entry.n, entry.p);
4588          link(entry, freshEnd);
4589          freshEnd = entry;
4590          freshEnd.n = null;
4591        }
4592      }
4593
4594
4595      /**
4596       * bidirectionally links two entries of the LRU linked list
4597       */
4598      function link(nextEntry, prevEntry) {
4599        if (nextEntry != prevEntry) {
4600          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
4601          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
4602        }
4603      }
4604    }
4605
4606
4607  /**
4608   * @ngdoc method
4609   * @name ng.$cacheFactory#info
4610   * @methodOf ng.$cacheFactory
4611   *
4612   * @description
4613   * Get information about all the of the caches that have been created
4614   *
4615   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
4616   */
4617    cacheFactory.info = function() {
4618      var info = {};
4619      forEach(caches, function(cache, cacheId) {
4620        info[cacheId] = cache.info();
4621      });
4622      return info;
4623    };
4624
4625
4626  /**
4627   * @ngdoc method
4628   * @name ng.$cacheFactory#get
4629   * @methodOf ng.$cacheFactory
4630   *
4631   * @description
4632   * Get access to a cache object by the `cacheId` used when it was created.
4633   *
4634   * @param {string} cacheId Name or id of a cache to access.
4635   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
4636   */
4637    cacheFactory.get = function(cacheId) {
4638      return caches[cacheId];
4639    };
4640
4641
4642    return cacheFactory;
4643  };
4644}
4645
4646/**
4647 * @ngdoc object
4648 * @name ng.$templateCache
4649 *
4650 * @description
4651 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
4652 * can load templates directly into the cache in a `script` tag, or by consuming the
4653 * `$templateCache` service directly.
4654 * 
4655 * Adding via the `script` tag:
4656 * <pre>
4657 * <html ng-app>
4658 * <head>
4659 * <script type="text/ng-template" id="templateId.html">
4660 *   This is the content of the template
4661 * </script>
4662 * </head>
4663 *   ...
4664 * </html>
4665 * </pre>
4666 * 
4667 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
4668 * the document, but it must be below the `ng-app` definition.
4669 * 
4670 * Adding via the $templateCache service:
4671 * 
4672 * <pre>
4673 * var myApp = angular.module('myApp', []);
4674 * myApp.run(function($templateCache) {
4675 *   $templateCache.put('templateId.html', 'This is the content of the template');
4676 * });
4677 * </pre>
4678 * 
4679 * To retrieve the template later, simply use it in your HTML:
4680 * <pre>
4681 * <div ng-include=" 'templateId.html' "></div>
4682 * </pre>
4683 * 
4684 * or get it via Javascript:
4685 * <pre>
4686 * $templateCache.get('templateId.html')
4687 * </pre>
4688 * 
4689 * See {@link ng.$cacheFactory $cacheFactory}.
4690 *
4691 */
4692function $TemplateCacheProvider() {
4693  this.$get = ['$cacheFactory', function($cacheFactory) {
4694    return $cacheFactory('templates');
4695  }];
4696}
4697
4698/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
4699 *
4700 * DOM-related variables:
4701 *
4702 * - "node" - DOM Node
4703 * - "element" - DOM Element or Node
4704 * - "$node" or "$element" - jqLite-wrapped node or element
4705 *
4706 *
4707 * Compiler related stuff:
4708 *
4709 * - "linkFn" - linking fn of a single directive
4710 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
4711 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
4712 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
4713 */
4714
4715
4716/**
4717 * @ngdoc function
4718 * @name ng.$compile
4719 * @function
4720 *
4721 * @description
4722 * Compiles an HTML string or DOM into a template and produces a template function, which
4723 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
4724 *
4725 * The compilation is a process of walking the DOM tree and matching DOM elements to
4726 * {@link ng.$compileProvider#methods_directive directives}.
4727 *
4728 * <div class="alert alert-warning">
4729 * **Note:** This document is an in-depth reference of all directive options.
4730 * For a gentle introduction to directives with examples of common use cases,
4731 * see the {@link guide/directive directive guide}.
4732 * </div>
4733 *
4734 * ## Comprehensive Directive API
4735 *
4736 * There are many different options for a directive.
4737 *
4738 * The difference resides in the return value of the factory function.
4739 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
4740 * or just the `postLink` function (all other properties will have the default values).
4741 *
4742 * <div class="alert alert-success">
4743 * **Best Practice:** It's recommended to use the "directive definition object" form.
4744 * </div>
4745 *
4746 * Here's an example directive declared with a Directive Definition Object:
4747 *
4748 * <pre>
4749 *   var myModule = angular.module(...);
4750 *
4751 *   myModule.directive('directiveName', function factory(injectables) {
4752 *     var directiveDefinitionObject = {
4753 *       priority: 0,
4754 *       template: '<div></div>
4754', // or // function(tElement, tAttrs) { ... },
4755 *       // or
4756 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
4757 *       replace: false,
4758 *       transclude: false,
4759 *       restrict: 'A',
4760 *       scope: false,
4761 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
4762 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
4763 *       compile: function compile(tElement, tAttrs, transclude) {
4764 *         return {
4765 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
4766 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
4767 *         }
4768 *         // or
4769 *         // return function postLink( ... ) { ... }
4770 *       },
4771 *       // or
4772 *       // link: {
4773 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
4774 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
4775 *       // }
4776 *       // or
4777 *       // link: function postLink( ... ) { ... }
4778 *     };
4779 *     return directiveDefinitionObject;
4780 *   });
4781 * </pre>
4782 *
4783 * <div class="alert alert-warning">
4784 * **Note:** Any unspecified options will use the default value. You can see the default values below.
4785 * </div>
4786 *
4787 * Therefore the above can be simplified as:
4788 *
4789 * <pre>
4790 *   var myModule = angular.module(...);
4791 *
4792 *   myModule.directive('directiveName', function factory(injectables) {
4793 *     var directiveDefinitionObject = {
4794 *       link: function postLink(scope, iElement, iAttrs) { ... }
4795 *     };
4796 *     return directiveDefinitionObject;
4797 *     // or
4798 *     // return function postLink(scope, iElement, iAttrs) { ... }
4799 *   });
4800 * </pre>
4801 *
4802 *
4803 *
4804 * ### Directive Definition Object
4805 *
4806 * The directive definition object provides instructions to the {@link api/ng.$compile
4807 * compiler}. The attributes are:
4808 *
4809 * #### `priority`
4810 * When there are multiple directives defined on a single DOM element, sometimes it
4811 * is necessary to specify the order in which the directives are applied. The `priority` is used
4812 * to sort the directives before their `compile` functions get called. Priority is defined as a
4813 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
4814 * are also run in priority order, but post-link functions are run in reverse order. The order
4815 * of directives with the same priority is undefined. The default priority is `0`.
4816 *
4817 * #### `terminal`
4818 * If set to true then the current `priority` will be the last set of directives
4819 * which will execute (any directives at the current priority will still execute
4820 * as the order of execution on same `priority` is undefined).
4821 *
4822 * #### `scope`
4823 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
4824 * same element request a new scope, only one new scope is created. The new scope rule does not
4825 * apply for the root of the template since the root of the template always gets a new scope.
4826 *
4827 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
4828 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
4829 * when creating reusable components, which should not accidentally read or modify data in the
4830 * parent scope.
4831 *
4832 * The 'isolate' scope takes an object hash which defines a set of local scope properties
4833 * derived from the parent scope. These local properties are useful for aliasing values for
4834 * templates. Locals definition is a hash of local scope property to its source:
4835 *
4836 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
4837 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
4838 *   attribute name is assumed to be the same as the local name.
4839 *   Given `<widget my-attr="hello {{name}}">` and widget definition
4840 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
4841 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
4842 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
4843 *   component scope).
4844 *
4845 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
4846 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
4847 *   name is specified then the attribute name is assumed to be the same as the local name.
4848 *   Given `<widget my-attr="parentModel">` and widget definition of
4849 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
4850 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
4851 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
4852 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
4853 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
4854 *
4855 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
4856 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
4857 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
4858 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
4859 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
4860 *   pass data from the isolated scope via an expression and to the parent scope, this can be
4861 *   done by passing a map of local variable names and values into the expression wrapper fn.
4862 *   For example, if the expression is `increment(amount)` then we can specify the amount value
4863 *   by calling the `localFn` as `localFn({amount: 22})`.
4864 *
4865 *
4866 *
4867 * #### `controller`
4868 * Controller constructor function. The controller is instantiated before the
4869 * pre-linking phase and it is shared with other directives (see
4870 * `require` attribute). This allows the directives to communicate with each other and augment
4871 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
4872 *
4873 * * `$scope` - Current scope associated with the element
4874 * * `$element` - Current element
4875 * * `$attrs` - Current attributes object for the element
4876 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
4877 *    The scope can be overridden by an optional first argument.
4878 *   `function([scope], cloneLinkingFn)`.
4879 *
4880 *
4881 * #### `require`
4882 * Require another directive and inject its controller as the fourth argument to the linking function. The
4883 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
4884 * injected argument will be an array in corresponding order. If no such directive can be
4885 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
4886 *
4887 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
4888 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
4889 * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
4890 * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
4891 *   `link` fn if not found.
4892 *
4893 *
4894 * #### `controllerAs`
4895 * Controller alias at the directive scope. An alias for the controller so it
4896 * can be referenced at the directive template. The directive needs to define a scope for this
4897 * configuration to be used. Useful in the case when directive is used as component.
4898 *
4899 *
4900 * #### `restrict`
4901 * String of subset of `EACM` which restricts the directive to a specific directive
4902 * declaration style. If omitted, the default (attributes only) is used.
4903 *
4904 * * `E` - Element name: `<my-directive></my-directive>`
4905 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
4906 * * `C` - Class: `<div class="my-directive: exp;"></div>`
4907 * * `M` - Comment: `<!-- directive: my-directive exp -->`
4908 *
4909 *
4910 * #### `template`
4911 * replace the current element with the contents of the HTML. The replacement process
4912 * migrates all of the attributes / classes from the old element to the new one. See the
4913 * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
4914 * Directives Guide} for an example.
4915 *
4916 * You can specify `template` as a string representing the template or as a function which takes
4917 * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
4918 * returns a string value representing the template.
4919 *
4920 *
4921 * #### `templateUrl`
4922 * Same as `template` but the template is loaded from the specified URL. Because
4923 * the template loading is asynchronous the compilation/linking is suspended until the template
4924 * is loaded.
4925 *
4926 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
4927 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
4928 * a string value representing the url.  In either case, the template URL is passed through {@link
4929 * api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}.
4930 *
4931 *
4932 * #### `replace`
4933 * specify where the template should be inserted. Defaults to `false`.
4934 *
4935 * * `true` - the template will replace the current element.
4936 * * `false` - the template will replace the contents of the current element.
4937 *
4938 *
4939 * #### `transclude`
4940 * compile the content of the element and make it available to the directive.
4941 * Typically used with {@link api/ng.directive:ngTransclude
4942 * ngTransclude}. The advantage of transclusion is that the linking function receives a
4943 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
4944 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
4945 * scope. This makes it possible for the widget to have private state, and the transclusion to
4946 * be bound to the parent (pre-`isolate`) scope.
4947 *
4948 * * `true` - transclude the content of the directive.
4949 * * `'element'` - transclude the whole element including any directives defined at lower priority.
4950 *
4951 *
4952 * #### `compile`
4953 *
4954 * <pre>
4955 *   function compile(tElement, tAttrs, transclude) { ... }
4956 * </pre>
4957 *
4958 * The compile function deals with transforming the template DOM. Since most directives do not do
4959 * template transformation, it is not used often. Examples that require compile functions are
4960 * directives that transform template DOM, such as {@link
4961 * api/ng.directive:ngRepeat ngRepeat}, or load the contents
4962 * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The
4963 * compile function takes the following arguments.
4964 *
4965 *   * `tElement` - template element - The element where the directive has been declared. It is
4966 *     safe to do template transformation on the element and child elements only.
4967 *
4968 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
4969 *     between all directive compile functions.
4970 *
4971 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
4972 *
4973 * <div class="alert alert-warning">
4974 * **Note:** The template instance and the link instance may be different objects if the template has
4975 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
4976 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
4977 * should be done in a linking function rather than in a compile function.
4978 * </div>
4979 *
4980 * <div class="alert alert-error">
4981 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
4982 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
4983 *   to the link function instead.
4984 * </div>
4985
4986 * A compile function can have a return value which can be either a function or an object.
4987 *
4988 * * returning a (post-link) function - is equivalent to registering the linking function via the
4989 *   `link` property of the config object when the compile function is empty.
4990 *
4991 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
4992 *   control when a linking function should be called during the linking phase. See info about
4993 *   pre-linking and post-linking functions below.
4994 *
4995 *
4996 * #### `link`
4997 * This property is used only if the `compile` property is not defined.
4998 *
4999 * <pre>
5000 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5001 * </pre>
5002 *
5003 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5004 * executed after the template has been cloned. This is where most of the directive logic will be
5005 * put.
5006 *
5007 *   * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
5008 *     directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}.
5009 *
5010 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5011 *     manipulate the children of the element only in `postLink` function since the children have
5012 *     already been linked.
5013 *
5014 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5015 *     between all directive linking functions.
5016 *
5017 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5018 *     element defines a controller. The controller is shared among all the directives, which allows
5019 *     the directives to use the controllers as a communication channel.
5020 *
5021 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5022 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5023 *     parameter of directive controllers.
5024 *     `function([scope], cloneLinkingFn)`.
5025 *
5026 *
5027 * #### Pre-linking function
5028 *
5029 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5030 * compiler linking function will fail to locate the correct elements for linking.
5031 *
5032 * #### Post-linking function
5033 *
5034 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5035 *
5036 * <a name="Attributes"></a>
5037 * ### Attributes
5038 *
5039 * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5040 * `link()` or `compile()` functions. It has a variety of uses.
5041 *
5042 * accessing *Normalized attribute names:*
5043 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5044 * the attributes object allows for normalized access to
5045 *   the attributes.
5046 *
5047 * * *Directive inter-communication:* All directives share the same instance of the attributes
5048 *   object which allows the directives to use the attributes object as inter directive
5049 *   communication.
5050 *
5051 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5052 *   allowing other directives to read the interpolated value.
5053 *
5054 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5055 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
5056 *   the only way to easily get the actual value because during the linking phase the interpolation
5057 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5058 *
5059 * <pre>
5060 * function linkingFn(scope, elm, attrs, ctrl) {
5061 *   // get the attribute value
5062 *   console.log(attrs.ngModel);
5063 *
5064 *   // change the attribute
5065 *   attrs.$set('ngModel', 'new value');
5066 *
5067 *   // observe changes to interpolated attribute
5068 *   attrs.$observe('ngModel', function(value) {
5069 *     console.log('ngModel has changed value to ' + value);
5070 *   });
5071 * }
5072 * </pre>
5073 *
5074 * Below is an example using `$compileProvider`.
5075 *
5076 * <div class="alert alert-warning">
5077 * **Note**: Typically directives are registered with `module.directive`. The example below is
5078 * to illustrate how `$compile` works.
5079 * </div>
5080 *
5081 <doc:example module="compile">
5082   <doc:source>
5083    <script>
5084      angular.module('compile', [], function($compileProvider) {
5085        // configure new 'compile' directive by passing a directive
5086        // factory function. The factory function injects the '$compile'
5087        $compileProvider.directive('compile', function($compile) {
5088          // directive factory creates a link function
5089          return function(scope, element, attrs) {
5090            scope.$watch(
5091              function(scope) {
5092                 // watch the 'compile' expression for changes
5093                return scope.$eval(attrs.compile);
5094              },
5095              function(value) {
5096                // when the 'compile' expression changes
5097                // assign it into the current DOM
5098                element.html(value);
5099
5100                // compile the new DOM and link it to the current
5101                // scope.
5102                // NOTE: we only compile .childNodes so that
5103                // we don't get into infinite loop compiling ourselves
5104                $compile(element.contents())(scope);
5105              }
5106            );
5107          };
5108        })
5109      });
5110
5111      function Ctrl($scope) {
5112        $scope.name = 'Angular';
5113        $scope.html = 'Hello {{name}}';
5114      }
5115    </script>
5116    <div ng-controller="Ctrl">
5117      <input ng-model="name"> <br>
5118      <textarea ng-model="html"></textarea> <br>
5119      <div compile="html"></div>
5120    </div>
5121   </doc:source>
5122   <doc:scenario>
5123     it('should auto compile', function() {
5124       expect(element('div[compile]').text()).toBe('Hello Angular');
5125       input('html').enter('{{name}}!');
5126       expect(element('div[compile]').text()).toBe('Angular!');
5127     });
5128   </doc:scenario>
5129 </doc:example>
5130
5131 *
5132 *
5133 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5134 * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
5135 * @param {number} maxPriority only apply directives lower then given priority (Only effects the
5136 *                 root element(s), not their children)
5137 * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
5138 * (a DOM element/tree) to a scope. Where:
5139 *
5140 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5141 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5142 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5143 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5144 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5145 *
5146 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5147 *      * `scope` - is the current scope with which the linking function is working with.
5148 *
5149 * Calling the linking function returns the element of the template. It is either the original
5150 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5151 *
5152 * After linking the view is not updated until after a call to $digest which typically is done by
5153 * Angular automatically.
5154 *
5155 * If you need access to the bound view, there are two ways to do it:
5156 *
5157 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5158 *   before you send them to the compiler and keep this reference around.
5159 *   <pre>
5160 *     var element = $compile('<p>{{total}}</p>')(scope);
5161 *   </pre>
5162 *
5163 * - if on the other hand, you need the element to be cloned, the view reference from the original
5164 *   example would not point to the clone, but rather to the original template that was cloned. In
5165 *   this case, you can access the clone via the cloneAttachFn:
5166 *   <pre>
5167 *     var templateElement = angular.element('<p>{{total}}</p>'),
5168 *         scope = ....;
5169 *
5170 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5171 *       //attach the clone to DOM document at the right place
5172 *     });
5173 *
5174 *     //now we have reference to the cloned DOM via `clonedElement`
5175 *   </pre>
5176 *
5177 *
5178 * For information on how the compiler works, see the
5179 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5180 */
5181
5182var $compileMinErr = minErr('$compile');
5183
5184/**
5185 * @ngdoc service
5186 * @name ng.$compileProvider
5187 * @function
5188 *
5189 * @description
5190 */
vendor: 4,665 bytes, lines 5191-5302
5191$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5192function $CompileProvider($provide, $$sanitizeUriProvider) {
5193  var hasDirectives = {},
5194      Suffix = 'Directive',
5195      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5196      CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5197
5198  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5199  // The assumption is that future DOM event attribute names will begin with
5200  // 'on' and be composed of only English letters.
5201  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5202
5203  /**
5204   * @ngdoc function
5205   * @name ng.$compileProvider#directive
5206   * @methodOf ng.$compileProvider
5207   * @function
5208   *
5209   * @description
5210   * Register a new directive with the compiler.
5211   *
5212   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5213   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5214   *    names and the values are the factories.
5215   * @param {function|Array} directiveFactory An injectable directive factory function. See
5216   *    {@link guide/directive} for more info.
5217   * @returns {ng.$compileProvider} Self for chaining.
5218   */
5219   this.directive = function registerDirective(name, directiveFactory) {
5220    assertNotHasOwnProperty(name, 'directive');
5221    if (isString(name)) {
5222      assertArg(directiveFactory, 'directiveFactory');
5223      if (!hasDirectives.hasOwnProperty(name)) {
5224        hasDirectives[name] = [];
5225        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5226          function($injector, $exceptionHandler) {
5227            var directives = [];
5228            forEach(hasDirectives[name], function(directiveFactory, index) {
5229              try {
5230                var directive = $injector.invoke(directiveFactory);
5231                if (isFunction(directive)) {
5232                  directive = { compile: valueFn(directive) };
5233                } else if (!directive.compile && directive.link) {
5234                  directive.compile = valueFn(directive.link);
5235                }
5236                directive.priority = directive.priority || 0;
5237                directive.index = index;
5238                directive.name = directive.name || name;
5239                directive.require = directive.require || (directive.controller && directive.name);
5240                directive.restrict = directive.restrict || 'A';
5241                directives.push(directive);
5242              } catch (e) {
5243                $exceptionHandler(e);
5244              }
5245            });
5246            return directives;
5247          }]);
5248      }
5249      hasDirectives[name].push(directiveFactory);
5250    } else {
5251      forEach(name, reverseParams(registerDirective));
5252    }
5253    return this;
5254  };
5255
5256
5257  /**
5258   * @ngdoc function
5259   * @name ng.$compileProvider#aHrefSanitizationWhitelist
5260   * @methodOf ng.$compileProvider
5261   * @function
5262   *
5263   * @description
5264   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5265   * urls during a[href] sanitization.
5266   *
5267   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5268   *
5269   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5270   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5271   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5272   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5273   *
5274   * @param {RegExp=} regexp New regexp to whitelist urls with.
5275   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5276   *    chaining otherwise.
5277   */
5278  this.aHrefSanitizationWhitelist = function(regexp) {
5279    if (isDefined(regexp)) {
5280      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5281      return this;
5282    } else {
5283      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5284    }
5285  };
5286
5287
5288  /**
5289   * @ngdoc function
5290   * @name ng.$compileProvider#imgSrcSanitizationWhitelist
5291   * @methodOf ng.$compileProvider
5292   * @function
5293   *
5294   * @description
5295   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5296   * urls during img[src] sanitization.
5297   *
5298   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5299   *
5300   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5301   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5302   * regular expression. If a match is found, the original url is 
5302written into the dom. Otherwise,
5303   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5304   *
5305   * @param {RegExp=} regexp New regexp to whitelist urls with.
5306   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5307   *    chaining otherwise.
5308   */
5309  this.imgSrcSanitizationWhitelist = function(regexp) {
5310    if (isDefined(regexp)) {
5311      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5312      return this;
5313    } else {
5314      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5315    }
5316  };
5317
5318  this.$get = [
5319            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5320            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5321    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5322             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5323
5324    var Attributes = function(element, attr) {
5325      this.$$element = element;
5326      this.$attr = attr || {};
5327    };
5328
5329    Attributes.prototype = {
5330      $normalize: directiveNormalize,
5331
5332
5333      /**
5334       * @ngdoc function
5335       * @name ng.$compile.directive.Attributes#$addClass
5336       * @methodOf ng.$compile.directive.Attributes
5337       * @function
5338       *
5339       * @description
5340       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5341       * are enabled then an animation will be triggered for the class addition.
5342       *
5343       * @param {string} classVal The className value that will be added to the element
5344       */
5345      $addClass : function(classVal) {
5346        if(classVal && classVal.length > 0) {
5347          $animate.addClass(this.$$element, classVal);
5348        }
5349      },
5350
5351      /**
5352       * @ngdoc function
5353       * @name ng.$compile.directive.Attributes#$removeClass
5354       * @methodOf ng.$compile.directive.Attributes
5355       * @function
5356       *
5357       * @description
5358       * Removes the CSS class value specified by the classVal parameter from the element. If
5359       * animations are enabled then an animation will be triggered for the class removal.
5360       *
5361       * @param {string} classVal The className value that will be removed from the element
5362       */
5363      $removeClass : function(classVal) {
5364        if(classVal && classVal.length > 0) {
5365          $animate.removeClass(this.$$element, classVal);
5366        }
5367      },
5368
5369      /**
5370       * @ngdoc function
5371       * @name ng.$compile.directive.Attributes#$updateClass
5372       * @methodOf ng.$compile.directive.Attributes
5373       * @function
5374       *
5375       * @description
5376       * Adds and removes the appropriate CSS class values to the element based on the difference
5377       * between the new and old CSS class values (specified as newClasses and oldClasses).
5378       *
5379       * @param {string} newClasses The current CSS className value
5380       * @param {string} oldClasses The former CSS className value
5381       */
5382      $updateClass : function(newClasses, oldClasses) {
5383        this.$removeClass(tokenDifference(oldClasses, newClasses));
5384        this.$addClass(tokenDifference(newClasses, oldClasses));
5385      },
5386
5387      /**
5388       * Set a normalized attribute on the element in a way such that all directives
5389       * can share the attribute. This function properly handles boolean attributes.
5390       * @param {string} key Normalized key. (ie ngAttribute)
5391       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5392       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5393       *     Defaults to true.
5394       * @param {string=} attrName Optional none normalized name. Defaults to key.
5395       */
5396      $set: function(key, value, writeAttr, attrName) {
5397        // TODO: decide whether or not to throw an error if "class"
5398        //is set through this function since it may cause $updateClass to
5399        //become unstable.
5400
5401        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5402            normalizedVal,
5403            nodeName;
5404
5405        if (booleanKey) {
5406          this.$$element.prop(key, value);
5407          attrName = booleanKey;
5408        }
5409
5410        this[key] = value;
5411
5412        // translate normalized key to actual key
5413        if (attrName) {
5414          this.$attr[key] = attrName;
5415        } else {
5416          attrName = this.$attr[key];
5417          if (!attrName) {
5418            this.$attr[key] = attrName = snake_case(key, '-');
5419          }
5420        }
5421
5422        nodeName = nodeName_(this.$$element);
5423
5424        // sanitize a[href] and img[src] values
5425        if ((nodeName === 'A' && key === 'href') ||
5426            (nodeName === 'IMG' && key === 'src')) {
5427          this[key] = value = $$sanitizeUri(value, key === 'src');
5428        }
5429
5430        if (writeAttr !== false) {
5431          if (value === null || value === undefined) {
5432            this.$$element.removeAttr(attrName);
5433          } else {
5434            this.$$element.attr(attrName, value);
5435          }
5436        }
5437
5438        // fire observers
5439        var $$observers = this.$$observers;
5440        $$observers && forEach($$observers[key], function(fn) {
5441          try {
5442            fn(value);
5443          } catch (e) {
5444            $exceptionHandler(e);
5445          }
5446        });
5447      },
5448
5449
5450      /**
5451       * @ngdoc function
5452       * @name ng.$compile.directive.Attributes#$observe
5453       * @methodOf ng.$compile.directive.Attributes
5454       * @function
5455       *
5456       * @description
5457       * Observes an interpolated attribute.
5458       *
5459       * The observer function will be invoked once during the next `$digest` following
5460       * compilation. The observer is then invoked whenever the interpolated value
5461       * changes.
5462       *
5463       * @param {string} key Normalized key. (ie ngAttribute) .
5464       * @param {function(interpolatedValue)} fn Function that will be called whenever
5465                the interpolated value of the attribute changes.
5466       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5467       * @returns {function()} the `fn` parameter.
5468       */
5469      $observe: function(key, fn) {
5470        var attrs = this,
5471            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5472            listeners = ($$observers[key] || ($$observers[key] = []));
5473
5474        listeners.push(fn);
5475        $rootScope.$evalAsync(function() {
5476          if (!listeners.$$inter) {
5477            // no one registered attribute interpolation function, so lets call it manually
5478            fn(attrs[key]);
5479          }
5480        });
5481        return fn;
5482      }
5483    };
5484
5485    var startSymbol = $interpolate.startSymbol(),
5486        endSymbol = $interpolate.endSymbol(),
5487        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5488            ? identity
5489            : function denormalizeTemplate(template) {
5490              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5491        },
5492        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5493
5494
5495    return compile;
5496
5497    //================================
5498
5499    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5500                        previousCompileContext) {
5501      if (!($compileNodes instanceof jqLite)) {
5502        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5503        // modify it.
5504        $compileNodes = jqLite($compileNodes);
5505      }
5506      // We can not compile top level text elements since text nodes can be merged and we will
5507      // not be able to attach scope data to them, so we will wrap them in <span>
5508      forEach($compileNodes, function(node, index){
5509        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5510          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5511        }
5512      });
5513      var compositeLinkFn =
5514              compileNodes($compileNodes, transcludeFn, $compileNodes,
5515                           maxPriority, ignoreDirective, previousCompileContext);
5516      safeAddClass($compileNodes, 'ng-scope');
5517      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
5518        assertArg(scope, 'scope');
5519        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5520        // and sometimes changes the structure of the DOM.
5521        var $linkNode = cloneConnectFn
5522          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5523          : $compileNodes;
5524
5525        forEach(transcludeControllers, function(instance, name) {
5526          $linkNode.data('$' + name + 'Controller', instance);
5527        });
5528
5529        // Attach scope only to non-text nodes.
5530        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5531          var node = $linkNode[i],
5532              nodeType = node.nodeType;
5533          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5534            $linkNode.eq(i).data('$scope', scope);
5535          }
5536        }
5537
5538        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5539        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
5540        return $linkNode;
5541      };
5542    }
5543
5544    function safeAddClass($element, className) {
5545      try {
5546        $element.addClass(className);
5547      } catch(e) {
5548        // ignore, since it means that we are trying to set class on
5549        // SVG element, where class name is read-only.
5550      }
5551    }
5552
5553    /**
5554     * Compile function matches each node in nodeList against the directives. Once all directives
5555     * for a particular node are collected their compile functions are executed. The compile
5556     * functions return values - the linking functions - are combined into a composite linking
5557     * function, which is the a linking function for the node.
5558     *
5559     * @param {NodeList} nodeList an array of nodes or NodeList to compile
5560     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
5561     *        scope argument is auto-generated to the new child of the transcluded parent scope.
5562     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
5563     *        the rootElement must be set the jqLite collection of the compile root. This is
5564     *        needed so that the jqLite collection items can be replaced with widgets.
5565     * @param {number=} maxPriority Max directive priority.
5566     * @returns {?function} A composite linking function of all of the matched directives or null.
5567     */
5568    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
5569                            previousCompileContext) {
5570      var linkFns = [],
5571          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
5572
5573      for (var i = 0; i < nodeList.length; i++) {
5574        attrs = new Attributes();
5575
5576        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
5577        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
5578                                        ignoreDirective);
5579
5580        nodeLinkFn = (directives.length)
5581            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
5582                                      null, [], [], previousCompileContext)
5583            : null;
5584
5585        if (nodeLinkFn && nodeLinkFn.scope) {
5586          safeAddClass(jqLite(nodeList[i]), 'ng-scope');
5587        }
5588
5589        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
5590                      !(childNodes = nodeList[i].childNodes) ||
5591                      !childNodes.length)
5592            ? null
5593            : compileNodes(childNodes,
5594                 nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
5595
5596        linkFns.push(nodeLinkFn, childLinkFn);
5597        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
5598        //use the previous context only for the first element in the virtual group
5599        previousCompileContext = null;
5600      }
5601
5602      // return a linking function if we have found anything, null otherwise
5603      return linkFnFound ? compositeLinkFn : null;
5604
5605      function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
5606        var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
5607
5608        // copy nodeList so that linking doesn't break due to live list updates.
5609        var nodeListLength = nodeList.length,
5610            stableNodeList = new Array(nodeListLength);
5611        for (i = 0; i < nodeListLength; i++) {
5612          stableNodeList[i] = nodeList[i];
5613        }
5614
5615        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
5616          node = stableNodeList[n];
5617          nodeLinkFn = linkFns[i++];
5618          childLinkFn = linkFns[i++];
5619          $node = jqLite(node);
5620
5621          if (nodeLinkFn) {
5622            if (nodeLinkFn.scope) {
5623              childScope = scope.$new();
5624              $node.data('$scope', childScope);
5625            } else {
5626              childScope = scope;
5627            }
5628            childTranscludeFn = nodeLinkFn.transclude;
5629            if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
5630              nodeLinkFn(childLinkFn, childScope, node, $rootElement,
5631                createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5632              );
5633            } else {
5634              nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
5635            }
5636          } else if (childLinkFn) {
5637            childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
5638          }
5639        }
5640      }
5641    }
5642
5643    function createBoundTranscludeFn(scope, transcludeFn) {
5644      return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
5645        var scopeCreated = false;
5646
5647        if (!transcludedScope) {
5648          transcludedScope = scope.$new();
5649          transcludedScope.$$transcluded = true;
5650          scopeCreated = true;
5651        }
5652
5653        var clone = transcludeFn(transcludedScope, cloneFn, controllers);
5654        if (scopeCreated) {
5655          clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
5656        }
5657        return clone;
5658      };
5659    }
5660
5661    /**
5662     * Looks for directives on the given node and adds them to the directive collection which is
5663     * sorted.
5664     *
5665     * @param node Node to search.
5666     * @param directives An array to which the directives are added to. This array is sorted before
5667     *        the function returns.
5668     * @param attrs The shared attrs object which is used to populate the normalized attributes.
5669     * @param {number=} maxPriority Max directive priority.
5670     */
5671    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
5672      var nodeType = node.nodeType,
5673          attrsMap = attrs.$attr,
5674          match,
5675          className;
5676
5677      switch(nodeType) {
5678        case 1: /* Element */
5679          // use the node name: <directive>
5680          addDirective(directives,
5681              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
5682
5683          // iterate over the attributes
5684          for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
5685                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
5686            var attrStartName = false;
5687            var attrEndName = false;
5688
5689            attr = nAttrs[j];
5690            if (!msie || msie >= 8 || attr.specified) {
5691              name = attr.name;
5692              // support ngAttr attribute binding
5693              ngAttrName = directiveNormalize(name);
5694              if (NG_ATTR_BINDING.test(ngAttrName)) {
5695                name = snake_case(ngAttrName.substr(6), '-');
5696              }
5697
5698              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
5699              if (ngAttrName === directiveNName + 'Start') {
5700                attrStartName = name;
5701                attrEndName = name.substr(0, name.length - 5) + 'end';
5702                name = name.substr(0, name.length - 6);
5703              }
5704
5705              nName = directiveNormalize(name.toLowerCase());
5706              attrsMap[nName] = name;
5707              attrs[nName] = value = trim(attr.value);
5708              if (getBooleanAttrName(node, nName)) {
5709                attrs[nName] = true; // presence means true
5710              }
5711              addAttrInterpolateDirective(node, directives, value, nName);
5712              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
5713                            attrEndName);
5714            }
5715          }
5716
5717          // use class as directive
5718          className = node.className;
5719          if (isString(className) && className !== '') {
5720            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
5721              nName = directiveNormalize(match[2]);
5722              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
5723                attrs[nName] = trim(match[3]);
5724              }
5725              className = className.substr(match.index + match[0].length);
5726            }
5727          }
5728          break;
5729        case 3: /* Text Node */
5730          addTextInterpolateDirective(directives, node.nodeValue);
5731          break;
5732        case 8: /* Comment */
5733          try {
5734            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
5735            if (match) {
5736              nName = directiveNormalize(match[1]);
5737              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
5738                attrs[nName] = trim(match[2]);
5739              }
5740            }
5741          } catch (e) {
5742            // turns out that under some circumstances IE9 throws errors when one attempts to read
5743            // comment's node value.
5744            // Just ignore it and continue. (Can't seem to reproduce in test case.)
5745          }
5746          break;
5747      }
5748
5749      directives.sort(byPriority);
5750      return directives;
5751    }
5752
5753    /**
5754     * Given a node with an directive-start it collects all of the siblings until it finds
5755     * directive-end.
5756     * @param node
5757     * @param attrStart
5758     * @param attrEnd
5759     * @returns {*}
5760     */
5761    function groupScan(node, attrStart, attrEnd) {
5762      var nodes = [];
5763      var depth = 0;
5764      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
5765        var startNode = node;
5766        do {
5767          if (!node) {
5768            throw $compileMinErr('uterdir',
5769                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
5770                      attrStart, attrEnd);
5771          }
5772          if (node.nodeType == 1 /** Element **/) {
5773            if (node.hasAttribute(attrStart)) depth++;
5774            if (node.hasAttribute(attrEnd)) depth--;
5775          }
5776          nodes.push(node);
5777          node = node.nextSibling;
5778        } while (depth > 0);
5779      } else {
5780        nodes.push(node);
5781      }
5782
5783      return jqLite(nodes);
5784    }
5785
5786    /**
5787     * Wrapper for linking function which converts normal linking function into a grouped
5788     * linking function.
5789     * @param linkFn
5790     * @param attrStart
5791     * @param attrEnd
5792     * @returns {Function}
5793     */
5794    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
5795      return function(scope, element, attrs, controllers, transcludeFn) {
5796        element = groupScan(element[0], attrStart, attrEnd);
5797        return linkFn(scope, element, attrs, controllers, transcludeFn);
5798      };
5799    }
5800
5801    /**
5802     * Once the directives have been collected, their compile functions are executed. This method
5803     * is responsible for inlining directive templates as well as terminating the application
5804     * of the directives if the terminal directive has been reached.
5805     *
5806     * @param {Array} directives Array of collected directives to execute their compile function.
5807     *        this needs to be pre-sorted by priority order.
5808     * @param {Node} compileNode The raw DOM node to apply the compile functions to
5809     * @param {Object} templateAttrs The shared attribute function
5810     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
5811     *                                                  scope argument is auto-generated to the new
5812     *                                                  child of the transcluded parent scope.
5813     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
5814     *                              argument has the root jqLite array so that we can replace nodes
5815     *                              on it.
5816     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
5817     *                                           compiling the transclusion.
5818     * @param {Array.<Function>} preLinkFns
5819     * @param {Array.<Function>} postLinkFns
5820     * @param {Object} previousCompileContext Context used for previous compilation of the current
5821     *                                        node
5822     * @returns linkFn
5823     */
5824    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
5825                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
5826                                   previousCompileContext) {
5827      previousCompileContext = previousCompileContext || {};
5828
5829      var terminalPriority = -Number.MAX_VALUE,
5830          newScopeDirective,
5831          controllerDirectives = previousCompileContext.controllerDirectives,
5832          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
5833          templateDirective = previousCompileContext.templateDirective,
5834          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
5835          hasTranscludeDirective = false,
5836          hasElementTranscludeDirective = false,
5837          $compileNode = templateAttrs.$$element = jqLite(compileNode),
5838          directive,
5839          directiveName,
5840          $template,
5841          replaceDirective = originalReplaceDirective,
5842          childTranscludeFn = transcludeFn,
5843          linkFn,
5844          directiveValue;
5845
5846      // executes all directives on the current element
5847      for(var i = 0, ii = directives.length; i < ii; i++) {
5848        directive = directives[i];
5849        var attrStart = directive.$$start;
5850        var attrEnd = directive.$$end;
5851
5852        // collect multiblock sections
5853        if (attrStart) {
5854          $compileNode = groupScan(compileNode, attrStart, attrEnd);
5855        }
5856        $template = undefined;
5857
5858        if (terminalPriority > directive.priority) {
5859          break; // prevent further processing of directives
5860        }
5861
5862        if (directiveValue = directive.scope) {
5863          newScopeDirective = newScopeDirective || directive;
5864
5865          // skip the check for directives with async templates, we'll check the derived sync
5866          // directive when the template arrives
5867          if (!directive.templateUrl) {
5868            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
5869                              $compileNode);
5870            if (isObject(directiveValue)) {
5871              newIsolateScopeDirective = directive;
5872            }
5873          }
5874        }
5875
5876        directiveName = directive.name;
5877
5878        if (!directive.templateUrl && directive.controller) {
5879          directiveValue = directive.controller;
5880          controllerDirectives = controllerDirectives || {};
5881          assertNoDuplicate("'" + directiveName + "' controller",
5882              controllerDirectives[directiveName], directive, $compileNode);
5883          controllerDirectives[directiveName] = directive;
5884        }
5885
5886        if (directiveValue = directive.transclude) {
5887          hasTranscludeDirective = true;
5888
5889          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
5890          // This option should only be used by directives that know how to how to safely handle element transclusion,
5891          // where the transcluded nodes are added or replaced after linking.
5892          if (!directive.$$tlb) {
5893            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
5894            nonTlbTranscludeDirective = directive;
5895          }
5896
5897          if (directiveValue == 'element') {
5898            hasElementTranscludeDirective = true;
5899            terminalPriority = directive.priority;
5900            $template = groupScan(compileNode, attrStart, attrEnd);
5901            $compileNode = templateAttrs.$$element =
5902                jqLite(document.createComment(' ' + directiveName + ': ' +
5903                                              templateAttrs[directiveName] + ' '));
5904            compileNode = $compileNode[0];
5905            replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
5906
5907            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
5908                                        replaceDirective && replaceDirective.name, {
5909                                          // Don't pass in:
5910                                          // - controllerDirectives - otherwise we'll create duplicates controllers
5911                                          // - newIsolateScopeDirective or templateDirective - comb
5911ining templates with
5912                                          //   element transclusion doesn't make sense.
5913                                          //
5914                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
5915                                          // on the same element more than once.
5916                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
5917                                        });
5918          } else {
5919            $template = jqLite(jqLiteClone(compileNode)).contents();
5920            $compileNode.empty(); // clear contents
5921            childTranscludeFn = compile($template, transcludeFn);
5922          }
5923        }
5924
5925        if (directive.template) {
5926          assertNoDuplicate('template', templateDirective, directive, $compileNode);
5927          templateDirective = directive;
5928
5929          directiveValue = (isFunction(directive.template))
5930              ? directive.template($compileNode, templateAttrs)
5931              : directive.template;
5932
5933          directiveValue = denormalizeTemplate(directiveValue);
5934
5935          if (directive.replace) {
5936            replaceDirective = directive;
5937            $template = jqLite('<div>' +
5938                                 trim(directiveValue) +
5939                               '</div>').contents();
5940            compileNode = $template[0];
5941
5942            if ($template.length != 1 || compileNode.nodeType !== 1) {
5943              throw $compileMinErr('tplrt',
5944                  "Template for directive '{0}' must have exactly one root element. {1}",
5945                  directiveName, '');
5946            }
5947
5948            replaceWith(jqCollection, $compileNode, compileNode);
5949
5950            var newTemplateAttrs = {$attr: {}};
5951
5952            // combine directives from the original node and from the template:
5953            // - take the array of directives for this element
5954            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
5955            // - collect directives from the template and sort them by priority
5956            // - combine directives as: processed + template + unprocessed
5957            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
5958            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
5959
5960            if (newIsolateScopeDirective) {
5961              markDirectivesAsIsolate(templateDirectives);
5962            }
5963            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
5964            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
5965
5966            ii = directives.length;
5967          } else {
5968            $compileNode.html(directiveValue);
5969          }
5970        }
5971
5972        if (directive.templateUrl) {
5973          assertNoDuplicate('template', templateDirective, directive, $compileNode);
5974          templateDirective = directive;
5975
5976          if (directive.replace) {
5977            replaceDirective = directive;
5978          }
5979
5980          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
5981              templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
5982                controllerDirectives: controllerDirectives,
5983                newIsolateScopeDirective: newIsolateScopeDirective,
5984                templateDirective: templateDirective,
5985                nonTlbTranscludeDirective: nonTlbTranscludeDirective
5986              });
5987          ii = directives.length;
5988        } else if (directive.compile) {
5989          try {
5990            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
5991            if (isFunction(linkFn)) {
5992              addLinkFns(null, linkFn, attrStart, attrEnd);
5993            } else if (linkFn) {
5994              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
5995            }
5996          } catch (e) {
5997            $exceptionHandler(e, startingTag($compileNode));
5998          }
5999        }
6000
6001        if (directive.terminal) {
6002          nodeLinkFn.terminal = true;
6003          terminalPriority = Math.max(terminalPriority, directive.priority);
6004        }
6005
6006      }
6007
6008      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6009      nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6010
6011      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6012      return nodeLinkFn;
6013
6014      ////////////////////
6015
6016      function addLinkFns(pre, post, attrStart, attrEnd) {
6017        if (pre) {
6018          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6019          pre.require = directive.require;
6020          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6021            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6022          }
6023          preLinkFns.push(pre);
6024        }
6025        if (post) {
6026          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6027          post.require = directive.require;
6028          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6029            post = cloneAndAnnotateFn(post, {isolateScope: true});
6030          }
6031          postLinkFns.push(post);
6032        }
6033      }
6034
6035
6036      function getControllers(require, $element, elementControllers) {
6037        var value, retrievalMethod = 'data', optional = false;
6038        if (isString(require)) {
6039          while((value = require.charAt(0)) == '^' || value == '?') {
6040            require = require.substr(1);
6041            if (value == '^') {
6042              retrievalMethod = 'inheritedData';
6043            }
6044            optional = optional || value == '?';
6045          }
6046          value = null;
6047
6048          if (elementControllers && retrievalMethod === 'data') {
6049            value = elementControllers[require];
6050          }
6051          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6052
6053          if (!value && !optional) {
6054            throw $compileMinErr('ctreq',
6055                "Controller '{0}', required by directive '{1}', can't be found!",
6056                require, directiveName);
6057          }
6058          return value;
6059        } else if (isArray(require)) {
6060          value = [];
6061          forEach(require, function(require) {
6062            value.push(getControllers(require, $element, elementControllers));
6063          });
6064        }
6065        return value;
6066      }
6067
6068
6069      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6070        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6071
6072        if (compileNode === linkNode) {
6073          attrs = templateAttrs;
6074        } else {
6075          attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6076        }
6077        $element = attrs.$$element;
6078
6079        if (newIsolateScopeDirective) {
6080          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6081          var $linkNode = jqLite(linkNode);
6082
6083          isolateScope = scope.$new(true);
6084
6085          if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6086            $linkNode.data('$isolateScope', isolateScope) ;
6087          } else {
6088            $linkNode.data('$isolateScopeNoTemplate', isolateScope);
6089          }
6090
6091
6092
6093          safeAddClass($linkNode, 'ng-isolate-scope');
6094
6095          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6096            var match = definition.match(LOCAL_REGEXP) || [],
6097                attrName = match[3] || scopeName,
6098                optional = (match[2] == '?'),
6099                mode = match[1], // @, =, or &
6100                lastValue,
6101                parentGet, parentSet, compare;
6102
6103            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6104
6105            switch (mode) {
6106
6107              case '@':
6108                attrs.$observe(attrName, function(value) {
6109                  isolateScope[scopeName] = value;
6110                });
6111                attrs.$$observers[attrName].$$scope = scope;
6112                if( attrs[attrName] ) {
6113                  // If the attribute has been provided then we trigger an interpolation to ensure
6114                  // the value is there for use in the link fn
6115                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6116                }
6117                break;
6118
6119              case '=':
6120                if (optional && !attrs[attrName]) {
6121                  return;
6122                }
6123                parentGet = $parse(attrs[attrName]);
6124                if (parentGet.literal) {
6125                  compare = equals;
6126                } else {
6127                  compare = function(a,b) { return a === b; };
6128                }
6129                parentSet = parentGet.assign || function() {
6130                  // reset the change, or we will throw this exception on every $digest
6131                  lastValue = isolateScope[scopeName] = parentGet(scope);
6132                  throw $compileMinErr('nonassign',
6133                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6134                      attrs[attrName], newIsolateScopeDirective.name);
6135                };
6136                lastValue = isolateScope[scopeName] = parentGet(scope);
6137                isolateScope.$watch(function parentValueWatch() {
6138                  var parentValue = parentGet(scope);
6139                  if (!compare(parentValue, isolateScope[scopeName])) {
6140                    // we are out of sync and need to copy
6141                    if (!compare(parentValue, lastValue)) {
6142                      // parent changed and it has precedence
6143                      isolateScope[scopeName] = parentValue;
6144                    } else {
6145                      // if the parent can be assigned then do so
6146                      parentSet(scope, parentValue = isolateScope[scopeName]);
6147                    }
6148                  }
6149                  return lastValue = parentValue;
6150                }, null, parentGet.literal);
6151                break;
6152
6153              case '&':
6154                parentGet = $parse(attrs[attrName]);
6155                isolateScope[scopeName] = function(locals) {
6156                  return parentGet(scope, locals);
6157                };
6158                break;
6159
6160              default:
6161                throw $compileMinErr('iscp',
6162                    "Invalid isolate scope definition for directive '{0}'." +
6163                    " Definition: {... {1}: '{2}' ...}",
6164                    newIsolateScopeDirective.name, scopeName, definition);
6165            }
6166          });
6167        }
6168        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6169        if (controllerDirectives) {
6170          forEach(controllerDirectives, function(directive) {
6171            var locals = {
6172              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6173              $element: $element,
6174              $attrs: attrs,
6175              $transclude: transcludeFn
6176            }, controllerInstance;
6177
6178            controller = directive.controller;
6179            if (controller == '@') {
6180              controller = attrs[directive.name];
6181            }
6182
6183            controllerInstance = $controller(controller, locals);
6184            // For directives with element transclusion the element is a comment,
6185            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6186            // clean up (http://bugs.jquery.com/ticket/8335).
6187            // Instead, we save the controllers for the element in a local hash and attach to .data
6188            // later, once we have the actual element.
6189            elementControllers[directive.name] = controllerInstance;
6190            if (!hasElementTranscludeDirective) {
6191              $element.data('$' + directive.name + 'Controller', controllerInstance);
6192            }
6193
6194            if (directive.controllerAs) {
6195              locals.$scope[directive.controllerAs] = controllerInstance;
6196            }
6197          });
6198        }
6199
6200        // PRELINKING
6201        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6202          try {
6203            linkFn = preLinkFns[i];
6204            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6205                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6206          } catch (e) {
6207            $exceptionHandler(e, startingTag($element));
6208          }
6209        }
6210
6211        // RECURSION
6212        // We only pass the isolate scope, if the isolate directive has a template,
6213        // otherwise the child elements do not belong to the isolate directive.
6214        var scopeToChild = scope;
6215        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6216          scopeToChild = isolateScope;
6217        }
6218        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6219
6220        // POSTLINKING
6221        for(i = postLinkFns.length - 1; i >= 0; i--) {
6222          try {
6223            linkFn = postLinkFns[i];
6224            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6225                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6226          } catch (e) {
6227            $exceptionHandler(e, startingTag($element));
6228          }
6229        }
6230
6231        // This is the function that is injected as `$transclude`.
6232        function controllersBoundTransclude(scope, cloneAttachFn) {
6233          var transcludeControllers;
6234
6235          // no scope passed
6236          if (arguments.length < 2) {
6237            cloneAttachFn = scope;
6238            scope = undefined;
6239          }
6240
6241          if (hasElementTranscludeDirective) {
6242            transcludeControllers = elementControllers;
6243          }
6244
6245          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6246        }
6247      }
6248    }
6249
6250    function markDirectivesAsIsolate(directives) {
6251      // mark all directives as needing isolate scope.
6252      for (var j = 0, jj = directives.length; j < jj; j++) {
6253        directives[j] = inherit(directives[j], {$$isolateScope: true});
6254      }
6255    }
6256
6257    /**
6258     * looks up the directive and decorates it with exception handling and proper parameters. We
6259     * call this the boundDirective.
6260     *
6261     * @param {string} name name of the directive to look up.
6262     * @param {string} location The directive must be found in specific format.
6263     *   String containing any of theses characters:
6264     *
6265     *   * `E`: element name
6266     *   * `A': attribute
6267     *   * `C`: class
6268     *   * `M`: comment
6269     * @returns true if directive was added.
6270     */
6271    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6272                          endAttrName) {
6273      if (name === ignoreDirective) return null;
6274      var match = null;
6275      if (hasDirectives.hasOwnProperty(name)) {
6276        for(var directive, directives = $injector.get(name + Suffix),
6277            i = 0, ii = directives.length; i<ii; i++) {
6278          try {
6279            directive = directives[i];
6280            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6281                 directive.restrict.indexOf(location) != -1) {
6282              if (startAttrName) {
6283                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6284              }
6285              tDirectives.push(directive);
6286              match = directive;
6287            }
6288          } catch(e) { $exceptionHandler(e); }
6289        }
6290      }
6291      return match;
6292    }
6293
6294
6295    /**
6296     * When the element is replaced with HTML template then the new attributes
6297     * on the template need to be merged with the existing attributes in the DOM.
6298     * The desired effect is to have both of the attributes present.
6299     *
6300     * @param {object} dst destination attributes (original DOM)
6301     * @param {object} src source attributes (from the directive template)
6302     */
6303    function mergeTemplateAttributes(dst, src) {
6304      var srcAttr = src.$attr,
6305          dstAttr = dst.$attr,
6306          $element = dst.$$element;
6307
6308      // reapply the old attributes to the new element
6309      forEach(dst, function(value, key) {
6310        if (key.charAt(0) != '$') {
6311          if (src[key]) {
6312            value += (key === 'style' ? ';' : ' ') + src[key];
6313          }
6314          dst.$set(key, value, true, srcAttr[key]);
6315        }
6316      });
6317
6318      // copy the new attributes on the old attrs object
6319      forEach(src, function(value, key) {
6320        if (key == 'class') {
6321          safeAddClass($element, value);
6322          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6323        } else if (key == 'style') {
6324          $element.attr('style', $element.attr('style') + ';' + value);
6325          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6326          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6327          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6328          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6329        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6330          dst[key] = value;
6331          dstAttr[key] = srcAttr[key];
6332        }
6333      });
6334    }
6335
6336
6337    function compileTemplateUrl(directives, $compileNode, tAttrs,
6338        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6339      var linkQueue = [],
6340          afterTemplateNodeLinkFn,
6341          afterTemplateChildLinkFn,
6342          beforeTemplateCompileNode = $compileNode[0],
6343          origAsyncDirective = directives.shift(),
6344          // The fact that we have to copy and patch the directive seems wrong!
6345          derivedSyncDirective = extend({}, origAsyncDirective, {
6346            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6347          }),
6348          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6349              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
6350              : origAsyncDirective.templateUrl;
6351
6352      $compileNode.empty();
6353
6354      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6355        success(function(content) {
6356          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6357
6358          content = denormalizeTemplate(content);
6359
6360          if (origAsyncDirective.replace) {
6361            $template = jqLite('<div>' + trim(content) + '</div>').contents();
6362            compileNode = $template[0];
6363
6364            if ($template.length != 1 || compileNode.nodeType !== 1) {
6365              throw $compileMinErr('tplrt',
6366                  "Template for directive '{0}' must have exactly one root element. {1}",
6367                  origAsyncDirective.name, templateUrl);
6368            }
6369
6370            tempTemplateAttrs = {$attr: {}};
6371            replaceWith($rootElement, $compileNode, compileNode);
6372            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6373
6374            if (isObject(origAsyncDirective.scope)) {
6375              markDirectivesAsIsolate(templateDirectives);
6376            }
6377            directives = templateDirectives.concat(directives);
6378            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6379          } else {
6380            compileNode = beforeTemplateCompileNode;
6381            $compileNode.html(content);
6382          }
6383
6384          directives.unshift(derivedSyncDirective);
6385
6386          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6387              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6388              previousCompileContext);
6389          forEach($rootElement, function(node, i) {
6390            if (node == compileNode) {
6391              $rootElement[i] = $compileNode[0];
6392            }
6393          });
6394          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6395
6396
6397          while(linkQueue.length) {
6398            var scope = linkQueue.shift(),
6399                beforeTemplateLinkNode = linkQueue.shift(),
6400                linkRootElement = linkQueue.shift(),
6401                boundTranscludeFn = linkQueue.shift(),
6402                linkNode = $compileNode[0];
6403
6404            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6405              // it was cloned therefore we have to clone as well.
6406              linkNode = jqLiteClone(compileNode);
6407              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6408            }
6409            if (afterTemplateNodeLinkFn.transclude) {
6410              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6411            } else {
6412              childBoundTranscludeFn = boundTranscludeFn;
6413            }
6414            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6415              childBoundTranscludeFn);
6416          }
6417          linkQueue = null;
6418        }).
6419        error(function(response, code, headers, config) {
6420          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6421        });
6422
6423      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6424        if (linkQueue) {
6425          linkQueue.push(scope);
6426          linkQueue.push(node);
6427          linkQueue.push(rootElement);
6428          linkQueue.push(boundTranscludeFn);
6429        } else {
6430          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6431        }
6432      };
6433    }
6434
6435
6436    /**
6437     * Sorting function for bound directives.
6438     */
6439    function byPriority(a, b) {
6440      var diff = b.priority - a.priority;
6441      if (diff !== 0) return diff;
6442      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6443      return a.index - b.index;
6444    }
6445
6446
6447    function assertNoDuplicate(what, previousDirective, directive, element) {
6448      if (previousDirective) {
6449        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6450            previousDirective.name, directive.name, what, startingTag(element));
6451      }
6452    }
6453
6454
6455    function addTextInterpolateDirective(directives, text) {
6456      var interpolateFn = $interpolate(text, true);
6457      if (interpolateFn) {
6458        directives.push({
6459          priority: 0,
6460          compile: valueFn(function textInterpolateLinkFn(scope, node) {
6461            var parent = node.parent(),
6462                bindings = parent.data('$binding') || [];
6463            bindings.push(interpolateFn);
6464            safeAddClass(parent.data('$binding', bindings), 'ng-binding');
6465            scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6466              node[0].nodeValue = value;
6467            });
6468          })
6469        });
6470      }
6471    }
6472
6473
6474    function getTrustedContext(node, attrNormalizedName) {
6475      if (attrNormalizedName == "srcdoc") {
6476        return $sce.HTML;
6477      }
6478      var tag = nodeName_(node);
6479      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6480      if (attrNormalizedName == "xlinkHref" ||
6481          (tag == "FORM" && attrNormalizedName == "action") ||
6482          (tag != "IMG" && (attrNormalizedName == "src" ||
6483                            attrNormalizedName == "ngSrc"))) {
6484        return $sce.RESOURCE_URL;
6485      }
6486    }
6487
6488
6489    function addAttrInterpolateDirective(node, directives, value, name) {
6490      var interpolateFn = $interpolate(value, true);
6491
6492      // no interpolation found -> ignore
6493      if (!interpolateFn) return;
6494
6495
6496      if (name === "multiple" && nodeName_(node) === "SELECT") {
6497        throw $compileMinErr("selmulti",
6498            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6499            startingTag(node));
6500      }
6501
6502      directives.push({
6503        priority: 100,
6504        compile: function() {
6505            return {
6506              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6507                var $$observers = (attr.$$observers || (attr.$$observers = {}));
6508
6509                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
6510                  throw $compileMinErr('nodomevents',
6511                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
6512                          "ng- versions (such as ng-click instead of onclick) instead.");
6513                }
6514
6515                // we need to interpolate again, in case the attribute value has been updated
6516                // (e.g. by another directive's compile function)
6517                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
6518
6519                // if attribute was updated so that there is no interpolation going on we don't want to
6520                // register any observers
6521                if (!interpolateFn) return;
6522
6523                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
6524                // actual attr value
6525                attr[name] = interpolateFn(scope);
6526                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6527                (attr.$$observers && attr.$$observers[name].$$scope || scope).
6528                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6529                    //special case for class attribute addition + removal
6530                    //so that class changes can tap into the animation
6531                    //hooks provided by the $animate service. Be sure to
6532                    //skip animations when the first digest occurs (when
6533                    //both the new and the old values are the same) since
6534                    //the CSS classes are the non-interpolated values
6535                    if(name === 'class' && newValue != oldValue) {
6536                      attr.$updateClass(newValue, oldValue);
6537                    } else {
6538                      attr.$set(name, newValue);
6539                    }
6540                  });
6541              }
6542            };
6543          }
6544      });
6545    }
6546
6547
6548    /**
6549     * This is a special jqLite.replaceWith, which can replace items which
6550     * have no parents, provided that the containing jqLite collection is provided.
6551     *
6552     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
6553     *                               in the root of the tree.
6554     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
6555     *                                  the shell, but replace its DOM node reference.
6556     * @param {Node} newNode The new DOM node.
6557     */
6558    function replaceWith($rootElement, elementsToRemove, newNode) {
6559      var firstElementToRemove = elementsToRemove[0],
6560          removeCount = elementsToRemove.length,
6561          parent = firstElementToRemove.parentNode,
6562          i, ii;
6563
6564      if ($rootElement) {
6565        for(i = 0, ii = $rootElement.length; i < ii; i++) {
6566          if ($rootElement[i] == firstElementToRemove) {
6567            $rootElement[i++] = newNode;
6568            for (var j = i, j2 = j + removeCount - 1,
6569                     jj = $rootElement.length;
6570                 j < jj; j++, j2++) {
6571              if (j2 < jj) {
6572                $rootElement[j] = $rootElement[j2];
6573              } else {
6574                delete $rootElement[j];
6575              }
6576            }
6577            $rootElement.length -= removeCount - 1;
6578            break;
6579          }
6580        }
6581      }
6582
6583      if (parent) {
6584        parent.replaceChild(newNode, firstElementToRemove);
6585      }
6586      var fragment = document.createDocumentFragment();
6587      fragment.appendChild(firstElementToRemove);
6588      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
6589      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
6590        var element = elementsToRemove[k];
6591        jqLite(element).remove(); // must do this way to clean up expando
6592        fragment.appendChild(element);
6593        delete elementsToRemove[k];
6594      }
6595
6596      elementsToRemove[0] = newNode;
6597      elementsToRemove.length = 1;
6598    }
6599
6600
6601    function cloneAndAnnotateFn(fn, annotation) {
6602      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
6603    }
6604  }];
6605}
6606
6607var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
6608/**
6609 * Converts all accepted directives format into proper directive name.
6610 * All of these will become 'myDirective':
6611 *   my:Directive
6612 *   my-directive
6613 *   x-my-directive
6614 *   data-my:directive
6615 *
6616 * Also there is special case for Moz prefix starting with upper case letter.
6617 * @param name Name to normalize
6618 */
6619function directiveNormalize(name) {
6620  return camelCase(name.replace(PREFIX_REGEXP, ''));
6621}
6622
6623/**
6624 * @ngdoc object
6625 * @name ng.$compile.directive.Attributes
6626 *
6627 * @description
6628 * A shared object between directive compile / linking functions which contains 
6628normalized DOM
6629 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
6630 * needed since all of these are treated as equivalent in Angular:
6631 *
6632 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
6633 */
6634
6635/**
6636 * @ngdoc property
6637 * @name ng.$compile.directive.Attributes#$attr
6638 * @propertyOf ng.$compile.directive.Attributes
6639 * @returns {object} A map of DOM element attribute names to the normalized name. This is
6640 *                   needed to do reverse lookup from normalized name back to actual name.
6641 */
6642
6643
6644/**
6645 * @ngdoc function
6646 * @name ng.$compile.directive.Attributes#$set
6647 * @methodOf ng.$compile.directive.Attributes
6648 * @function
6649 *
6650 * @description
6651 * Set DOM element attribute value.
6652 *
6653 *
6654 * @param {string} name Normalized element attribute name of the property to modify. The name is
6655 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
6656 *          property to the original name.
6657 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
6658 */
6659
6660
6661
6662/**
6663 * Closure compiler type information
6664 */
6665
6666function nodesetLinkingFn(
6667  /* angular.Scope */ scope,
6668  /* NodeList */ nodeList,
6669  /* Element */ rootElement,
6670  /* function(Function) */ boundTranscludeFn
6671){}
6672
6673function directiveLinkingFn(
6674  /* nodesetLinkingFn */ nodesetLinkingFn,
6675  /* angular.Scope */ scope,
6676  /* Node */ node,
6677  /* Element */ rootElement,
6678  /* function(Function) */ boundTranscludeFn
6679){}
6680
6681function tokenDifference(str1, str2) {
6682  var values = '',
6683      tokens1 = str1.split(/\s+/),
6684      tokens2 = str2.split(/\s+/);
6685
6686  outer:
6687  for(var i = 0; i < tokens1.length; i++) {
6688    var token = tokens1[i];
6689    for(var j = 0; j < tokens2.length; j++) {
6690      if(token == tokens2[j]) continue outer;
6691    }
6692    values += (values.length > 0 ? ' ' : '') + token;
6693  }
6694  return values;
6695}
6696
6697/**
6698 * @ngdoc object
6699 * @name ng.$controllerProvider
6700 * @description
6701 * The {@link ng.$controller $controller service} is used by Angular to create new
6702 * controllers.
6703 *
6704 * This provider allows controller registration via the
6705 * {@link ng.$controllerProvider#methods_register register} method.
6706 */
6707function $ControllerProvider() {
6708  var controllers = {},
6709      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
6710
6711
6712  /**
6713   * @ngdoc function
6714   * @name ng.$controllerProvider#register
6715   * @methodOf ng.$controllerProvider
6716   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
6717   *    the names and the values are the constructors.
6718   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
6719   *    annotations in the array notation).
6720   */
6721  this.register = function(name, constructor) {
6722    assertNotHasOwnProperty(name, 'controller');
6723    if (isObject(name)) {
6724      extend(controllers, name);
6725    } else {
6726      controllers[name] = constructor;
6727    }
6728  };
6729
6730
6731  this.$get = ['$injector', '$window', function($injector, $window) {
6732
6733    /**
6734     * @ngdoc function
6735     * @name ng.$controller
6736     * @requires $injector
6737     *
6738     * @param {Function|string} constructor If called with a function then it's considered to be the
6739     *    controller constructor function. Otherwise it's considered to be a string which is used
6740     *    to retrieve the controller constructor using the following steps:
6741     *
6742     *    * check if a controller with given name is registered via `$controllerProvider`
6743     *    * check if evaluating the string on the current scope returns a constructor
6744     *    * check `window[constructor]` on the global `window` object
6745     *
6746     * @param {Object} locals Injection locals for Controller.
6747     * @return {Object} Instance of given controller.
6748     *
6749     * @description
6750     * `$controller` service is responsible for instantiating controllers.
6751     *
6752     * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
6753     * a service, so that one can override this service with {@link https://gist.github.com/1649788
6754     * BC version}.
6755     */
6756    return function(expression, locals) {
6757      var instance, match, constructor, identifier;
6758
6759      if(isString(expression)) {
6760        match = expression.match(CNTRL_REG),
6761        constructor = match[1],
6762        identifier = match[3];
6763        expression = controllers.hasOwnProperty(constructor)
6764            ? controllers[constructor]
6765            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
6766
6767        assertArgFn(expression, constructor, true);
6768      }
6769
6770      instance = $injector.instantiate(expression, locals);
6771
6772      if (identifier) {
6773        if (!(locals && typeof locals.$scope == 'object')) {
6774          throw minErr('$controller')('noscp',
6775              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
6776              constructor || expression.name, identifier);
6777        }
6778
6779        locals.$scope[identifier] = instance;
6780      }
6781
6782      return instance;
6783    };
6784  }];
6785}
6786
6787/**
6788 * @ngdoc object
6789 * @name ng.$document
6790 * @requires $window
6791 *
6792 * @description
6793 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
6794 */
6795function $DocumentProvider(){
6796  this.$get = ['$window', function(window){
6797    return jqLite(window.document);
6798  }];
6799}
6800
6801/**
6802 * @ngdoc function
6803 * @name ng.$exceptionHandler
6804 * @requires $log
6805 *
6806 * @description
6807 * Any uncaught exception in angular expressions is delegated to this service.
6808 * The default implementation simply delegates to `$log.error` which logs it into
6809 * the browser console.
6810 * 
6811 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
6812 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
6813 *
6814 * ## Example:
6815 * 
6816 * <pre>
6817 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
6818 *     return function (exception, cause) {
6819 *       exception.message += ' (caused by "' + cause + '")';
6820 *       throw exception;
6821 *     };
6822 *   });
6823 * </pre>
6824 * 
6825 * This example will override the normal action of `$exceptionHandler`, to make angular
6826 * exceptions fail hard when they happen, instead of just logging to the console.
6827 *
6828 * @param {Error} exception Exception associated with the error.
6829 * @param {string=} cause optional information about the context in which
6830 *       the error was thrown.
6831 *
6832 */
6833function $ExceptionHandlerProvider() {
6834  this.$get = ['$log', function($log) {
6835    return function(exception, cause) {
6836      $log.error.apply($log, arguments);
6837    };
6838  }];
6839}
6840
6841/**
6842 * Parse headers into key value object
6843 *
6844 * @param {string} headers Raw headers as a string
6845 * @returns {Object} Parsed headers as key value object
6846 */
6847function parseHeaders(headers) {
6848  var parsed = {}, key, val, i;
6849
6850  if (!headers) return parsed;
6851
6852  forEach(headers.split('\n'), function(line) {
6853    i = line.indexOf(':');
6854    key = lowercase(trim(line.substr(0, i)));
6855    val = trim(line.substr(i + 1));
6856
6857    if (key) {
6858      if (parsed[key]) {
6859        parsed[key] += ', ' + val;
6860      } else {
6861        parsed[key] = val;
6862      }
6863    }
6864  });
6865
6866  return parsed;
6867}
6868
6869
6870/**
6871 * Returns a function that provides access to parsed headers.
6872 *
6873 * Headers are lazy parsed when first requested.
6874 * @see parseHeaders
6875 *
6876 * @param {(string|Object)} headers Headers to provide access to.
6877 * @returns {function(string=)} Returns a getter function which if called with:
6878 *
6879 *   - if called with single an argument returns a single header value or null
6880 *   - if called with no arguments returns an object containing all headers.
6881 */
6882function headersGetter(headers) {
6883  var headersObj = isObject(headers) ? headers : undefined;
6884
6885  return function(name) {
6886    if (!headersObj) headersObj =  parseHeaders(headers);
6887
6888    if (name) {
6889      return headersObj[lowercase(name)] || null;
6890    }
6891
6892    return headersObj;
6893  };
6894}
6895
6896
6897/**
6898 * Chain all given functions
6899 *
6900 * This function is used for both request and response transforming
6901 *
6902 * @param {*} data Data to transform.
6903 * @param {function(string=)} headers Http headers getter fn.
6904 * @param {(function|Array.<function>)} fns Function or an array of functions.
6905 * @returns {*} Transformed data.
6906 */
6907function transformData(data, headers, fns) {
6908  if (isFunction(fns))
6909    return fns(data, headers);
6910
6911  forEach(fns, function(fn) {
6912    data = fn(data, headers);
6913  });
6914
6915  return data;
6916}
6917
6918
6919function isSuccess(status) {
6920  return 200 <= status && status < 300;
6921}
6922
6923
6924function $HttpProvider() {
6925  var JSON_START = /^\s*(\[|\{[^\{])/,
6926      JSON_END = /[\}\]]\s*$/,
6927      PROTECTION_PREFIX = /^\)\]\}',?\n/,
6928      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
6929
6930  var defaults = this.defaults = {
6931    // transform incoming response data
6932    transformResponse: [function(data) {
6933      if (isString(data)) {
6934        // strip json vulnerability protection prefix
6935        data = data.replace(PROTECTION_PREFIX, '');
6936        if (JSON_START.test(data) && JSON_END.test(data))
6937          data = fromJson(data);
6938      }
6939      return data;
6940    }],
6941
6942    // transform outgoing request data
6943    transformRequest: [function(d) {
6944      return isObject(d) && !isFile(d) ? toJson(d) : d;
6945    }],
6946
6947    // default headers
6948    headers: {
6949      common: {
6950        'Accept': 'application/json, text/plain, */*'
6951      },
6952      post:   copy(CONTENT_TYPE_APPLICATION_JSON),
6953      put:    copy(CONTENT_TYPE_APPLICATION_JSON),
6954      patch:  copy(CONTENT_TYPE_APPLICATION_JSON)
6955    },
6956
6957    xsrfCookieName: 'XSRF-TOKEN',
6958    xsrfHeaderName: 'X-XSRF-TOKEN'
6959  };
6960
6961  /**
6962   * Are ordered by request, i.e. they are applied in the same order as the
6963   * array, on request, but reverse order, on response.
6964   */
6965  var interceptorFactories = this.interceptors = [];
6966
6967  /**
6968   * For historical reasons, response interceptors are ordered by the order in which
6969   * they are applied to the response. (This is the opposite of interceptorFactories)
6970   */
6971  var responseInterceptorFactories = this.responseInterceptors = [];
6972
6973  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
6974      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
6975
6976    var defaultCache = $cacheFactory('$http');
6977
6978    /**
6979     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
6980     * The reversal is needed so that we can build up the interception chain around the
6981     * server request.
6982     */
6983    var reversedInterceptors = [];
6984
6985    forEach(interceptorFactories, function(interceptorFactory) {
6986      reversedInterceptors.unshift(isString(interceptorFactory)
6987          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
6988    });
6989
6990    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
6991      var responseFn = isString(interceptorFactory)
6992          ? $injector.get(interceptorFactory)
6993          : $injector.invoke(interceptorFactory);
6994
6995      /**
6996       * Response interceptors go before "around" interceptors (no real reason, just
6997       * had to pick one.) But they are already reversed, so we can't use unshift, hence
6998       * the splice.
6999       */
7000      reversedInterceptors.splice(index, 0, {
7001        response: function(response) {
7002          return responseFn($q.when(response));
7003        },
7004        responseError: function(response) {
7005          return responseFn($q.reject(response));
7006        }
7007      });
7008    });
7009
7010
7011    /**
7012     * @ngdoc function
7013     * @name ng.$http
7014     * @requires $httpBackend
7015     * @requires $browser
7016     * @requires $cacheFactory
7017     * @requires $rootScope
7018     * @requires $q
7019     * @requires $injector
7020     *
7021     * @description
7022     * The `$http` service is a core Angular service that facilitates communication with the remote
7023     * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
7024     * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
7025     *
7026     * For unit testing applications that use `$http` service, see
7027     * {@link ngMock.$httpBackend $httpBackend mock}.
7028     *
7029     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7030     * $resource} service.
7031     *
7032     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7033     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7034     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7035     *
7036     *
7037     * # General usage
7038     * The `$http` service is a function which takes a single argument — a configuration object —
7039     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7040     * with two $http specific methods: `success` and `error`.
7041     *
7042     * <pre>
7043     *   $http({method: 'GET', url: '/someUrl'}).
7044     *     success(function(data, status, headers, config) {
7045     *       // this callback will be called asynchronously
7046     *       // when the response is available
7047     *     }).
7048     *     error(function(data, status, headers, config) {
7049     *       // called asynchronously if an error occurs
7050     *       // or server returns response with an error status.
7051     *     });
7052     * </pre>
7053     *
7054     * Since the returned value of calling the $http function is a `promise`, you can also use
7055     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7056     * an object representing the response. See the API signature and type info below for more
7057     * details.
7058     *
7059     * A response status code between 200 and 299 is considered a success status and
7060     * will result in the success callback being called. Note that if the response is a redirect,
7061     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7062     * called for such responses.
7063     *
7064     * # Writing Unit Tests that use $http
7065     * When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
7066     * {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
7067     * request using trained responses.
7068     *
7069     * ```
7070     * $httpBackend.expectGET(...);
7071     * $http.get(...);
7072     * $httpBackend.flush();
7073     * ```
7074     *
7075     * # Shortcut methods
7076     *
7077     * Since all invocations of the $http service require passing in an HTTP method and URL, and
7078     * POST/PUT requests require request data to be provided as well, shortcut methods
7079     * were created:
7080     *
7081     * <pre>
7082     *   $http.get('/someUrl').success(successCallback);
7083     *   $http.post('/someUrl', data).success(successCallback);
7084     * </pre>
7085     *
7086     * Complete list of shortcut methods:
7087     *
7088     * - {@link ng.$http#methods_get $http.get}
7089     * - {@link ng.$http#methods_head $http.head}
7090     * - {@link ng.$http#methods_post $http.post}
7091     * - {@link ng.$http#methods_put $http.put}
7092     * - {@link ng.$http#methods_delete $http.delete}
7093     * - {@link ng.$http#methods_jsonp $http.jsonp}
7094     *
7095     *
7096     * # Setting HTTP Headers
7097     *
7098     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7099     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7100     * object, which currently contains this default configuration:
7101     *
7102     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7103     *   - `Accept: application/json, text/plain, * / *`
7104     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7105     *   - `Content-Type: application/json`
7106     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7107     *   - `Content-Type: application/json`
7108     *
7109     * To add or overwrite these defaults, simply add or remove a property from these configuration
7110     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7111     * with the lowercased HTTP method name as the key, e.g.
7112     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7113     *
7114     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7115     * fashion. For example:
7116     *
7117     * ```
7118     * module.run(function($http) {
7119     *   $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
7120     * });
7121     * ```
7122     *
7123     * In addition, you can supply a `headers` property in the config object passed when
7124     * calling `$http(config)`, which overrides the defaults without changing them globally.
7125     *
7126     *
7127     * # Transforming Requests and Responses
7128     *
7129     * Both requests and responses can be transformed using transform functions. By default, Angular
7130     * applies these transformations:
7131     *
7132     * Request transformations:
7133     *
7134     * - If the `data` property of the request configuration object contains an object, serialize it
7135     *   into JSON format.
7136     *
7137     * Response transformations:
7138     *
7139     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7140     *  - If JSON response is detected, deserialize it using a JSON parser.
7141     *
7142     * To globally augment or override the default transforms, modify the
7143     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7144     * properties. These properties are by default an array of transform functions, which allows you
7145     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7146     * also decide to completely override any default transformations by assigning your
7147     * transformation functions to these properties directly without the array wrapper.  These defaults
7148     * are again available on the $http factory at run-time, which may be useful if you have run-time
7149     * services you wish to be involved in your transformations.
7150     *
7151     * Similarly, to locally override the request/response transforms, augment the
7152     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7153     * into `$http`.
7154     *
7155     *
7156     * # Caching
7157     *
7158     * To enable caching, set the request configuration `cache` property to `true` (to use default
7159     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7160     * When the cache is enabled, `$http` stores the response from the server in the specified
7161     * cache. The next time the same request is made, the response is served from the cache without
7162     * sending a request to the server.
7163     *
7164     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7165     * the same way that real requests are.
7166     *
7167     * If there are multiple GET requests for the same URL that should be cached using the same
7168     * cache, but the cache is not populated yet, only one request to the server will be made and
7169     * the remaining requests will be fulfilled using the response from the first request.
7170     *
7171     * You can change the default cache to a new object (built with
7172     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7173     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7174     * their `cache` property to `true` will now use this cache object.
7175     *
7176     * If you set the default cache to `false` then only requests that specify their own custom
7177     * cache object will be cached.
7178     *
7179     * # Interceptors
7180     *
7181     * Before you start creating interceptors, be sure to understand the
7182     * {@link ng.$q $q and deferred/promise APIs}.
7183     *
7184     * For purposes of global error handling, authentication, or any kind of synchronous or
7185     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7186     * able to intercept requests before they are handed to the server and
7187     * responses before they are handed over to the application code that
7188     * initiated these requests. The interceptors leverage the {@link ng.$q
7189     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7190     *
7191     * The interceptors are service factories that are registered with the `$httpProvider` by
7192     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7193     * injected with dependencies (if specified) and returns the interceptor.
7194     *
7195     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7196     *
7197     *   * `request`: interceptors get called with http `config` object. The function is free to
7198     *     modify the `config` or create a new one. The function needs to return the `config`
7199     *     directly or as a promise.
7200     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7201     *     resolved with a rejection.
7202     *   * `response`: interceptors get called with http `response` object. The function is free to
7203     *     modify the `response` or create a new one. The function needs to return the `response`
7204     *     directly or as a promise.
7205     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7206     *     resolved with a rejection.
7207     *
7208     *
7209     * <pre>
7210     *   // register the interceptor as a service
7211     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7212     *     return {
7213     *       // optional method
7214     *       'request': function(config) {
7215     *         // do something on success
7216     *         return config || $q.when(config);
7217     *       },
7218     *
7219     *       // optional method
7220     *      'requestError': function(rejection) {
7221     *         // do something on error
7222     *         if (canRecover(rejection)) {
7223     *           return responseOrNewPromise
7224     *         }
7225     *         return $q.reject(rejection);
7226     *       },
7227     *
7228     *
7229     *
7230     *       // optional method
7231     *       'response': function(response) {
7232     *         // do something on success
7233     *         return response || $q.when(response);
7234     *       },
7235     *
7236     *       // optional method
7237     *      'responseError': function(rejection) {
7238     *         // do something on error
7239     *         if (canRecover(rejection)) {
7240     *           return responseOrNewPromise
7241     *         }
7242     *         return $q.reject(rejection);
7243     *       }
7244     *     };
7245     *   });
7246     *
7247     *   $httpProvider.interceptors.push('myHttpInterceptor');
7248     *
7249     *
7250     *   // alternatively, register the interceptor via an anonymous factory
7251     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7252     *     return {
7253     *      'request': function(config) {
7254     *          // same as above
7255     *       },
7256     *
7257     *       'response': function(response) {
7258     *          // same as above
7259     *       }
7260     *     };
7261     *   });
7262     * </pre>
7263     *
7264     * # Response interceptors (DEPRECATED)
7265     *
7266     * Before you start creating interceptors, be sure to understand the
7267     * {@link ng.$q $q and deferred/promise APIs}.
7268     *
7269     * For purposes of global error handling, authentication or any kind of synchronous or
7270     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7271     * responses for http requests before they are handed over to the application code that
7272     * initiated these requests. The response interceptors leverage the {@link ng.$q
7273     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7274     *
7275     * The interceptors are service factories that are registered with the $httpProvider by
7276     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7277     * injected with dependencies (if specified) and returns the interceptor  — a function that
7278     * takes a {@link ng.$q promise} and returns the original or a new promise.
7279     *
7280     * <pre>
7281     *   // register the interceptor as a service
7282     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7283     *     return function(promise) {
7284     *       return promise.then(function(response) {
7285     *         // do something on success
7286     *         return response;
7287     *       }, function(response) {
7288     *         // do something on error
7289     *         if (canRecover(response)) {
7290     *           return responseOrNewPromise
7291     *         }
7292     *         return $q.reject(response);
7293     *       });
7294     *     }
7295     *   });
7296     *
7297     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7298     *
7299     *
7300     *   // register the interceptor via an anonymous factory
7301     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7302     *     return function(promise) {
7303     *       // same as above
7304     *     }
7305     *   });
7306     * </pre>
7307     *
7308     *
7309     * # Security Considerations
7310     *
7311     * When designing web applications, consider security threats from:
7312     *
7313     * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
7314     *   JSON vulnerability}
7315     * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
7316     *
7317     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7318     * pre-configured with strategies that address these issues, but for this to work backend server
7319     * cooperation is required.
7320     *
7321     * ## JSON Vulnerability Protection
7322     *
7323     * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
7324     * JSON vulnerability} allows third party website to turn your JSON resource URL into
7325     * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
7326     * counter this your server can prefix all JSON requests with following str
7326ing `")]}',\n"`.
7327     * Angular will automatically strip the prefix before processing it as JSON.
7328     *
7329     * For example if your server needs to return:
7330     * <pre>
7331     * ['one','two']
7332     * </pre>
7333     *
7334     * which is vulnerable to attack, your server can return:
7335     * <pre>
7336     * )]}',
7337     * ['one','two']
7338     * </pre>
7339     *
7340     * Angular will strip the prefix, before processing the JSON.
7341     *
7342     *
7343     * ## Cross Site Request Forgery (XSRF) Protection
7344     *
7345     * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
7346     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7347     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7348     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7349     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7350     * the XHR came from JavaScript running on your domain. The header will not be set for
7351     * cross-domain requests.
7352     *
7353     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7354     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7355     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7356     * that only JavaScript running on your domain could have sent the request. The token must be
7357     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7358     * making up its own tokens). We recommend that the token is a digest of your site's
7359     * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt}
7360     * for added security.
7361     *
7362     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7363     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7364     * or the per-request config object.
7365     *
7366     *
7367     * @param {object} config Object describing the request to be made and how it should be
7368     *    processed. The object has following properties:
7369     *
7370     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7371     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7372     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7373     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7374     *      JSONified.
7375     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7376     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7377     *      HTTP headers to send to the server. If the return value of a function is null, the
7378     *      header will not be sent.
7379     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7380     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7381     *    - **transformRequest** –
7382     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7383     *      transform function or an array of such functions. The transform function takes the http
7384     *      request body and headers and returns its transformed (typically serialized) version.
7385     *    - **transformResponse** –
7386     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7387     *      transform function or an array of such functions. The transform function takes the http
7388     *      response body and headers and returns its transformed (typically deserialized) version.
7389     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7390     *      GET request, otherwise if a cache instance built with
7391     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7392     *      caching.
7393     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7394     *      that should abort the request when resolved.
7395     *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
7396     *      XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
7397     *      requests with credentials} for more information.
7398     *    - **responseType** - `{string}` - see {@link
7399     *      https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
7400     *
7401     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7402     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7403     *   method takes two arguments a success and an error callback which will be called with a
7404     *   response object. The `success` and `error` methods take a single argument - a function that
7405     *   will be called when the request succeeds or fails respectively. The arguments passed into
7406     *   these functions are destructured representation of the response object passed into the
7407     *   `then` method. The response object has these properties:
7408     *
7409     *   - **data** – `{string|Object}` – The response body transformed with the transform
7410     *     functions.
7411     *   - **status** – `{number}` – HTTP status code of the response.
7412     *   - **headers** – `{function([headerName])}` – Header getter function.
7413     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7414     *
7415     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7416     *   requests. This is primarily meant to be used for debugging purposes.
7417     *
7418     *
7419     * @example
7420<example>
7421<file name="index.html">
7422  <div ng-controller="FetchCtrl">
7423    <select ng-model="method">
7424      <option>GET</option>
7425      <option>JSONP</option>
7426    </select>
7427    <input type="text" ng-model="url" size="80"/>
7428    <button ng-click="fetch()">fetch</button><br>
7429    <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7430    <button
7431      ng-click="updateModel('JSONP',
7432                    'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7433      Sample JSONP
7434    </button>
7435    <button
7436      ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7437        Invalid JSONP
7438      </button>
7439    <pre>http status code: {{status}}</pre>
7440    <pre>http response data: {{data}}</pre>
7441  </div>
7442</file>
7443<file name="script.js">
7444  function FetchCtrl($scope, $http, $templateCache) {
7445    $scope.method = 'GET';
7446    $scope.url = 'http-hello.html';
7447
7448    $scope.fetch = function() {
7449      $scope.code = null;
7450      $scope.response = null;
7451
7452      $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7453        success(function(data, status) {
7454          $scope.status = status;
7455          $scope.data = data;
7456        }).
7457        error(function(data, status) {
7458          $scope.data = data || "Request failed";
7459          $scope.status = status;
7460      });
7461    };
7462
7463    $scope.updateModel = function(method, url) {
7464      $scope.method = method;
7465      $scope.url = url;
7466    };
7467  }
7468</file>
7469<file name="http-hello.html">
7470  Hello, $http!
7471</file>
7472<file name="scenario.js">
7473  it('should make an xhr GET request', function() {
7474    element(':button:contains("Sample GET")').click();
7475    element(':button:contains("fetch")').click();
7476    expect(binding('status')).toBe('200');
7477    expect(binding('data')).toMatch(/Hello, \$http!/);
7478  });
7479
7480  it('should make a JSONP request to angularjs.org', function() {
7481    element(':button:contains("Sample JSONP")').click();
7482    element(':button:contains("fetch")').click();
7483    expect(binding('status')).toBe('200');
7484    expect(binding('data')).toMatch(/Super Hero!/);
7485  });
7486
7487  it('should make JSONP request to invalid URL and invoke the error handler',
7488      function() {
7489    element(':button:contains("Invalid JSONP")').click();
7490    element(':button:contains("fetch")').click();
7491    expect(binding('status')).toBe('0');
7492    expect(binding('data')).toBe('Request failed');
7493  });
7494</file>
7495</example>
7496     */
7497    function $http(requestConfig) {
7498      var config = {
7499        transformRequest: defaults.transformRequest,
7500        transformResponse: defaults.transformResponse
7501      };
7502      var headers = mergeHeaders(requestConfig);
7503
7504      extend(config, requestConfig);
7505      config.headers = headers;
7506      config.method = uppercase(config.method);
7507
7508      var xsrfValue = urlIsSameOrigin(config.url)
7509          ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
7510          : undefined;
7511      if (xsrfValue) {
7512        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
7513      }
7514
7515
7516      var serverRequest = function(config) {
7517        headers = config.headers;
7518        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
7519
7520        // strip content-type if data is undefined
7521        if (isUndefined(config.data)) {
7522          forEach(headers, function(value, header) {
7523            if (lowercase(header) === 'content-type') {
7524                delete headers[header];
7525            }
7526          });
7527        }
7528
7529        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
7530          config.withCredentials = defaults.withCredentials;
7531        }
7532
7533        // send request
7534        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
7535      };
7536
7537      var chain = [serverRequest, undefined];
7538      var promise = $q.when(config);
7539
7540      // apply interceptors
7541      forEach(reversedInterceptors, function(interceptor) {
7542        if (interceptor.request || interceptor.requestError) {
7543          chain.unshift(interceptor.request, interceptor.requestError);
7544        }
7545        if (interceptor.response || interceptor.responseError) {
7546          chain.push(interceptor.response, interceptor.responseError);
7547        }
7548      });
7549
7550      while(chain.length) {
7551        var thenFn = chain.shift();
7552        var rejectFn = chain.shift();
7553
7554        promise = promise.then(thenFn, rejectFn);
7555      }
7556
7557      promise.success = function(fn) {
7558        promise.then(function(response) {
7559          fn(response.data, response.status, response.headers, config);
7560        });
7561        return promise;
7562      };
7563
7564      promise.error = function(fn) {
7565        promise.then(null, function(response) {
7566          fn(response.data, response.status, response.headers, config);
7567        });
7568        return promise;
7569      };
7570
7571      return promise;
7572
7573      function transformResponse(response) {
7574        // make a copy since the response must be cacheable
7575        var resp = extend({}, response, {
7576          data: transformData(response.data, response.headers, config.transformResponse)
7577        });
7578        return (isSuccess(response.status))
7579          ? resp
7580          : $q.reject(resp);
7581      }
7582
7583      function mergeHeaders(config) {
7584        var defHeaders = defaults.headers,
7585            reqHeaders = extend({}, config.headers),
7586            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
7587
7588        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
7589
7590        // execute if header value is function
7591        execHeaders(defHeaders);
7592        execHeaders(reqHeaders);
7593
7594        // using for-in instead of forEach to avoid unecessary iteration after header has been found
7595        defaultHeadersIteration:
7596        for (defHeaderName in defHeaders) {
7597          lowercaseDefHeaderName = lowercase(defHeaderName);
7598
7599          for (reqHeaderName in reqHeaders) {
7600            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
7601              continue defaultHeadersIteration;
7602            }
7603          }
7604
7605          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
7606        }
7607
7608        return reqHeaders;
7609
7610        function execHeaders(headers) {
7611          var headerContent;
7612
7613          forEach(headers, function(headerFn, header) {
7614            if (isFunction(headerFn)) {
7615              headerContent = headerFn();
7616              if (headerContent != null) {
7617                headers[header] = headerContent;
7618              } else {
7619                delete headers[header];
7620              }
7621            }
7622          });
7623        }
7624      }
7625    }
7626
7627    $http.pendingRequests = [];
7628
7629    /**
7630     * @ngdoc method
7631     * @name ng.$http#get
7632     * @methodOf ng.$http
7633     *
7634     * @description
7635     * Shortcut method to perform `GET` request.
7636     *
7637     * @param {string} url Relative or absolute URL specifying the destination of the request
7638     * @param {Object=} config Optional configuration object
7639     * @returns {HttpPromise} Future object
7640     */
7641
7642    /**
7643     * @ngdoc method
7644     * @name ng.$http#delete
7645     * @methodOf ng.$http
7646     *
7647     * @description
7648     * Shortcut method to perform `DELETE` request.
7649     *
7650     * @param {string} url Relative or absolute URL specifying the destination of the request
7651     * @param {Object=} config Optional configuration object
7652     * @returns {HttpPromise} Future object
7653     */
7654
7655    /**
7656     * @ngdoc method
7657     * @name ng.$http#head
7658     * @methodOf ng.$http
7659     *
7660     * @description
7661     * Shortcut method to perform `HEAD` request.
7662     *
7663     * @param {string} url Relative or absolute URL specifying the destination of the request
7664     * @param {Object=} config Optional configuration object
7665     * @returns {HttpPromise} Future object
7666     */
7667
7668    /**
7669     * @ngdoc method
7670     * @name ng.$http#jsonp
7671     * @methodOf ng.$http
7672     *
7673     * @description
7674     * Shortcut method to perform `JSONP` request.
7675     *
7676     * @param {string} url Relative or absolute URL specifying the destination of the request.
7677     *                     Should contain `JSON_CALLBACK` string.
7678     * @param {Object=} config Optional configuration object
7679     * @returns {HttpPromise} Future object
7680     */
7681    createShortMethods('get', 'delete', 'head', 'jsonp');
7682
7683    /**
7684     * @ngdoc method
7685     * @name ng.$http#post
7686     * @methodOf ng.$http
7687     *
7688     * @description
7689     * Shortcut method to perform `POST` request.
7690     *
7691     * @param {string} url Relative or absolute URL specifying the destination of the request
7692     * @param {*} data Request content
7693     * @param {Object=} config Optional configuration object
7694     * @returns {HttpPromise} Future object
7695     */
7696
7697    /**
7698     * @ngdoc method
7699     * @name ng.$http#put
7700     * @methodOf ng.$http
7701     *
7702     * @description
7703     * Shortcut method to perform `PUT` request.
7704     *
7705     * @param {string} url Relative or absolute URL specifying the destination of the request
7706     * @param {*} data Request content
7707     * @param {Object=} config Optional configuration object
7708     * @returns {HttpPromise} Future object
7709     */
7710    createShortMethodsWithData('post', 'put');
7711
7712        /**
7713         * @ngdoc property
7714         * @name ng.$http#defaults
7715         * @propertyOf ng.$http
7716         *
7717         * @description
7718         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
7719         * default headers, withCredentials as well as request and response transformations.
7720         *
7721         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
7722         */
7723    $http.defaults = defaults;
7724
7725
7726    return $http;
7727
7728
7729    function createShortMethods(names) {
7730      forEach(arguments, function(name) {
7731        $http[name] = function(url, config) {
7732          return $http(extend(config || {}, {
7733            method: name,
7734            url: url
7735          }));
7736        };
7737      });
7738    }
7739
7740
7741    function createShortMethodsWithData(name) {
7742      forEach(arguments, function(name) {
7743        $http[name] = function(url, data, config) {
7744          return $http(extend(config || {}, {
7745            method: name,
7746            url: url,
7747            data: data
7748          }));
7749        };
7750      });
7751    }
7752
7753
7754    /**
7755     * Makes the request.
7756     *
7757     * !!! ACCESSES CLOSURE VARS:
7758     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
7759     */
7760    function sendReq(config, reqData, reqHeaders) {
7761      var deferred = $q.defer(),
7762          promise = deferred.promise,
7763          cache,
7764          cachedResp,
7765          url = buildUrl(config.url, config.params);
7766
7767      $http.pendingRequests.push(config);
7768      promise.then(removePendingReq, removePendingReq);
7769
7770
7771      if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
7772        cache = isObject(config.cache) ? config.cache
7773              : isObject(defaults.cache) ? defaults.cache
7774              : defaultCache;
7775      }
7776
7777      if (cache) {
7778        cachedResp = cache.get(url);
7779        if (isDefined(cachedResp)) {
7780          if (cachedResp.then) {
7781            // cached request has already been sent, but there is no response yet
7782            cachedResp.then(removePendingReq, removePendingReq);
7783            return cachedResp;
7784          } else {
7785            // serving from cache
7786            if (isArray(cachedResp)) {
7787              resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
7788            } else {
7789              resolvePromise(cachedResp, 200, {});
7790            }
7791          }
7792        } else {
7793          // put the promise for the non-transformed response into cache as a placeholder
7794          cache.put(url, promise);
7795        }
7796      }
7797
7798      // if we won't have the response in cache, send the request to the backend
7799      if (isUndefined(cachedResp)) {
7800        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
7801            config.withCredentials, config.responseType);
7802      }
7803
7804      return promise;
7805
7806
7807      /**
7808       * Callback registered to $httpBackend():
7809       *  - caches the response if desired
7810       *  - resolves the raw $http promise
7811       *  - calls $apply
7812       */
7813      function done(status, response, headersString) {
7814        if (cache) {
7815          if (isSuccess(status)) {
7816            cache.put(url, [status, response, parseHeaders(headersString)]);
7817          } else {
7818            // remove promise from the cache
7819            cache.remove(url);
7820          }
7821        }
7822
7823        resolvePromise(response, status, headersString);
7824        if (!$rootScope.$$phase) $rootScope.$apply();
7825      }
7826
7827
7828      /**
7829       * Resolves the raw $http promise.
7830       */
7831      function resolvePromise(response, status, headers) {
7832        // normalize internal statuses to 0
7833        status = Math.max(status, 0);
7834
7835        (isSuccess(status) ? deferred.resolve : deferred.reject)({
7836          data: response,
7837          status: status,
7838          headers: headersGetter(headers),
7839          config: config
7840        });
7841      }
7842
7843
7844      function removePendingReq() {
7845        var idx = indexOf($http.pendingRequests, config);
7846        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
7847      }
7848    }
7849
7850
7851    function buildUrl(url, params) {
7852          if (!params) return url;
7853          var parts = [];
7854          forEachSorted(params, function(value, key) {
7855            if (value === null || isUndefined(value)) return;
7856            if (!isArray(value)) value = [value];
7857
7858            forEach(value, function(v) {
7859              if (isObject(v)) {
7860                v = toJson(v);
7861              }
7862              parts.push(encodeUriQuery(key) + '=' +
7863                         encodeUriQuery(v));
7864            });
7865          });
7866          return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
7867        }
7868
7869
7870  }];
7871}
7872
7873function createXhr(method) {
7874  // IE8 doesn't support PATCH method, but the ActiveX object does
7875  /* global ActiveXObject */
7876  return (msie <= 8 && lowercase(method) === 'patch')
7877      ? new ActiveXObject('Microsoft.XMLHTTP')
7878      : new window.XMLHttpRequest();
7879}
7880
7881
7882/**
7883 * @ngdoc object
7884 * @name ng.$httpBackend
7885 * @requires $browser
7886 * @requires $window
7887 * @requires $document
7888 *
7889 * @description
7890 * HTTP backend used by the {@link ng.$http service} that delegates to
7891 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
7892 *
7893 * You should never need to use this service directly, instead use the higher-level abstractions:
7894 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
7895 *
7896 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
7897 * $httpBackend} which can be trained with responses.
7898 */
7899function $HttpBackendProvider() {
7900  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
7901    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
7902  }];
7903}
7904
7905function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
7906  var ABORTED = -1;
7907
7908  // TODO(vojta): fix the signature
7909  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
7910    var status;
7911    $browser.$$incOutstandingRequestCount();
7912    url = url || $browser.url();
7913
7914    if (lowercase(method) == 'jsonp') {
7915      var callbackId = '_' + (callbacks.counter++).toString(36);
7916      callbacks[callbackId] = function(data) {
7917        callbacks[callbackId].data = data;
7918      };
7919
7920      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
7921          function() {
7922        if (callbacks[callbackId].data) {
7923          completeRequest(callback, 200, callbacks[callbackId].data);
7924        } else {
7925          completeRequest(callback, status || -2);
7926        }
7927        callbacks[callbackId] = angular.noop;
7928      });
7929    } else {
7930
7931      var xhr = createXhr(method);
7932
7933      xhr.open(method, url, true);
7934      forEach(headers, function(value, key) {
7935        if (isDefined(value)) {
7936            xhr.setRequestHeader(key, value);
7937        }
7938      });
7939
7940      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
7941      // response is in the cache. the promise api will ensure that to the app code the api is
7942      // always async
7943      xhr.onreadystatechange = function() {
7944        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
7945        // xhrs that are resolved while the app is in the background (see #5426).
7946        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
7947        // continuing
7948        //
7949        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
7950        // Safari respectively.
7951        if (xhr && xhr.readyState == 4) {
7952          var responseHeaders = null,
7953              response = null;
7954
7955          if(status !== ABORTED) {
7956            responseHeaders = xhr.getAllResponseHeaders();
7957
7958            // responseText is the old-school way of retrieving response (supported by IE8 & 9)
7959            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
7960            response = ('response' in xhr) ? xhr.response : xhr.responseText;
7961          }
7962
7963          completeRequest(callback,
7964              status || xhr.status,
7965              response,
7966              responseHeaders);
7967        }
7968      };
7969
7970      if (withCredentials) {
7971        xhr.withCredentials = true;
7972      }
7973
7974      if (responseType) {
7975        xhr.responseType = responseType;
7976      }
7977
7978      xhr.send(post || null);
7979    }
7980
7981    if (timeout > 0) {
7982      var timeoutId = $browserDefer(timeoutRequest, timeout);
7983    } else if (timeout && timeout.then) {
7984      timeout.then(timeoutRequest);
7985    }
7986
7987
7988    function timeoutRequest() {
7989      status = ABORTED;
7990      jsonpDone && jsonpDone();
7991      xhr && xhr.abort();
7992    }
7993
7994    function completeRequest(callback, status, response, headersString) {
7995      // cancel timeout and subsequent timeout promise resolution
7996      timeoutId && $browserDefer.cancel(timeoutId);
7997      jsonpDone = xhr = null;
7998
7999      // fix status code when it is 0 (0 status is undocumented).
8000      // Occurs when accessing file resources.
8001      // On Android 4.1 stock browser it occurs while retrieving files from application cache.
8002      status = (status === 0) ? (response ? 200 : 404) : status;
8003
8004      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8005      status = status == 1223 ? 204 : status;
8006
8007      callback(status, response, headersString);
8008      $browser.$$completeOutstandingRequest(noop);
8009    }
8010  };
8011
8012  function jsonpReq(url, done) {
8013    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8014    // - fetches local scripts via XHR and evals them
8015    // - adds and immediately removes script elements from the document
8016    var script = rawDocument.createElement('script'),
8017        doneWrapper = function() {
8018          script.onreadystatechange = script.onload = script.onerror = null;
8019          rawDocument.body.removeChild(script);
8020          if (done) done();
8021        };
8022
8023    script.type = 'text/javascript';
8024    script.src = url;
8025
8026    if (msie && msie <= 8) {
8027      script.onreadystatechange = function() {
8028        if (/loaded|complete/.test(script.readyState)) {
8029          doneWrapper();
8030        }
8031      };
8032    } else {
8033      script.onload = script.onerror = function() {
8034        doneWrapper();
8035      };
8036    }
8037
8038    rawDocument.body.appendChild(script);
8039    return doneWrapper;
8040  }
8041}
8042
8043var $interpolateMinErr = minErr('$interpolate');
8044
8045/**
8046 * @ngdoc object
8047 * @name ng.$interpolateProvider
8048 * @function
8049 *
8050 * @description
8051 *
8052 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8053 *
8054 * @example
8055<doc:example module="customInterpolationApp">
8056<doc:source>
8057<script>
8058  var customInterpolationApp = angular.module('customInterpolationApp', []);
8059
8060  customInterpolationApp.config(function($interpolateProvider) {
8061    $interpolateProvider.startSymbol('//');
8062    $interpolateProvider.endSymbol('//');
8063  });
8064
8065
8066  customInterpolationApp.controller('DemoController', function DemoController() {
8067      this.label = "This binding is brought you by // interpolation symbols.";
8068  });
8069</script>
8070<div ng-app="App" ng-controller="DemoController as demo">
8071    //demo.label//
8072</div>
8073</doc:source>
8074<doc:scenario>
8075 it('should interpolate binding with custom symbols', function() {
8076  expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
8077 });
8078</doc:scenario>
8079</doc:example>
8080 */
8081function $InterpolateProvider() {
8082  var startSymbol = '{{';
8083  var endSymbol = '}}';
8084
8085  /**
8086   * @ngdoc method
8087   * @name ng.$interpolateProvider#startSymbol
8088   * @methodOf ng.$interpolateProvider
8089   * @description
8090   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8091   *
8092   * @param {string=} value new value to set the starting symbol to.
8093   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8094   */
8095  this.startSymbol = function(value){
8096    if (value) {
8097      startSymbol = value;
8098      return this;
8099    } else {
8100      return startSymbol;
8101    }
8102  };
8103
8104  /**
8105   * @ngdoc method
8106   * @name ng.$interpolateProvider#endSymbol
8107   * @methodOf ng.$interpolateProvider
8108   * @description
8109   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8110   *
8111   * @param {string=} value new value to set the ending symbol to.
8112   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8113   */
8114  this.endSymbol = function(value){
8115    if (value) {
8116      endSymbol = value;
8117      return this;
8118    } else {
8119      return endSymbol;
8120    }
8121  };
8122
8123
8124  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8125    var startSymbolLength = startSymbol.length,
8126        endSymbolLength = endSymbol.length;
8127
8128    /**
8129     * @ngdoc function
8130     * @name ng.$interpolate
8131     * @function
8132     *
8133     * @requires $parse
8134     * @requires $sce
8135     *
8136     * @description
8137     *
8138     * Compiles a string with markup into an interpolation function. This service is used by the
8139     * HTML {@link ng.$compile $compile} service for data binding. See
8140     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8141     * interpolation markup.
8142     *
8143     *
8144       <pre>
8145         var $interpolate = ...; // injected
8146         var exp = $interpolate('Hello {{name | uppercase}}!');
8147         expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8148       </pre>
8149     *
8150     *
8151     * @param {string} text The text with markup to interpolate.
8152     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8153     *    embedded expression in order to return an interpolation function. Strings with no
8154     *    embedded expression will return null for the interpolation function.
8155     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8156     *    result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
8157     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8158     *    provides Strict Contextual Escaping for details.
8159     * @returns {function(context)} an interpolation function which is used to compute the
8160     *    interpolated string. The function has these parameters:
8161     *
8162     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8163     *      against.
8164     *
8165     */
8166    function $interpolate(text, mustHaveExpression, trustedContext) {
8167      var startIndex,
8168          endIndex,
8169          index = 0,
8170          parts = [],
8171          length = text.length,
8172          hasInterpolation = false,
8173          fn,
8174          exp,
8175          concat = [];
8176
8177      while(index < length) {
8178        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8179             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8180          (index != startIndex) && parts.push(text.substring(index, startIndex));
8181          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8182          fn.exp = exp;
8183          index = endIndex + endSymbolLength;
8184          hasInterpolation = true;
8185        } else {
8186          // we did not find anything, so we have to add the remainder to the parts array
8187          (index != length) && parts.push(text.substring(index));
8188          index = length;
8189        }
8190      }
8191
8192      if (!(length = parts.length)) {
8193        // we added, nothing, must have been an empty string.
8194        parts.push('');
8195        length = 1;
8196      }
8197
8198      // Concatenating expressions makes it hard to reason about whether some combination of
8199      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8200      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8201      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8202      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8203      // the load when auditing for XSS issues.
8204      if (trustedContext && parts.length > 1) {
8205          throw $interpolateMinErr('noconcat',
8206              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8207              "interpolations that concatenate multiple expressions when a trusted value is " +
8208              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8209      }
8210
8211      if (!mustHaveExpression  || hasInterpolation) {
8212        concat.length = length;
8213        fn = function(context) {
8214          try {
8215            for(var i = 0, ii = length, part; i<ii; i++) {
8216              if (typeof (part = parts[i]) == 'function') {
8217                part = part(context);
8218                if (trustedContext) {
8219                  part = $sce.getTrusted(trustedContext, part);
8220                } else {
8221                  part = $sce.valueOf(part);
8222                }
8223                if (part === null || isUndefined(part)) {
8224                  part = '';
8225                } else if (typeof part != 'string') {
8226                  part = toJson(part);
8227                }
8228              }
8229              concat[i] = part;
8230            }
8231            return concat.join('');
8232          }
8233          catch(err) {
8234            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8235                err.toString());
8236            $exceptionHandler(newErr);
8237          }
8238        };
8239        fn.exp = text;
8240        fn.parts = parts;
8241        return fn;
8242      }
8243    }
8244
8245
8246    /**
8247     * @ngdoc method
8248     * @name ng.$interpolate#startSymbol
8249     * @methodOf ng.$interpolate
8250     * @description
8251     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8252     *
8253     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8254     * the symbol.
8255     *
8256     * @returns {string} start symbol.
8257     */
8258    $interpolate.startSymbol = function() {
8259      return startSymbol;
8260    };
8261
8262
8263    /**
8264     * @ngdoc method
8265     * @name ng.$interpolate#endSymbol
8266     * @methodOf ng.$interpolate
8267     * @description
8268     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8269     *
8270     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8271     * the symbol.
8272     *
8273     * @returns {string} start symbol.
8274     */
8275    $interpolate.endSymbol = function() {
8276      return endSymbol;
8277    };
8278
8279    return $interpolate;
8280  }];
8281}
8282
8283function $IntervalProvider() {
8284  this.$get = ['$rootScope', '$window', '$q',
8285       function($rootScope,   $window,   $q) {
8286    var intervals = {};
8287
8288
8289     /**
8290      * @ngdoc function
8291      * @name ng.$interval
8292      *
8293      * @description
8294      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8295      * milliseconds.
8296      *
8297      * The return value of registering an interval function is a promise. This promise will be
8298      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8299      * run indefinitely if `count` is not defined. The value of the notification will be the
8300      * number of iterations that have run.
8301      * To cancel an interval, call `$interval.cancel(promise)`.
8302      *
8303      * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
8304      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8305      * time.
8306      *
8307      * <div class="alert alert-warning">
8308      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8309      * with them.  In particular they are not automatically destroyed when a controller's scope or a
8310      * directive's element are destroyed.
8311      * You should take this into consideration and make sure to always cancel the interval at the
8312      * appropriate moment.  See the example below for more details on how and when to do this.
8313      * </div>
8314      *
8315      * @param {function()} fn A function that should be called repeatedly.
8316      * @param {number} delay Number of milliseconds between each function call.
8317      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8318      *   indefinitely.
8319      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8320      *   will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
8321      * @returns {promise} A promise which will be notified on each iteration.
8322      *
8323      * @example
8324      <doc:example module="time">
8325        <doc:source>
8326          <script>
8327            function Ctrl2($scope,$interval) {
8328              $scope.format = 'M/d/yy h:mm:ss a';
8329              $scope.blood_1 = 100;
8330              $scope.blood_2 = 120;
8331
8332              var stop;
8333              $scope.fight = function() {
8334                // Don't start a new fight if we are already fighting
8335                if ( angular.isDefined(stop) ) return;
8336
8337                stop = $interval(function() {
8338                  if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8339                      $scope.blood_1 = $scope.blood_1 - 3;
8340                      $scope.blood_2 = $scope.blood_2 - 4;
8341                  } else {
8342                      $scope.stopFight();
8343                  }
8344                }, 100);
8345              };
8346
8347              $scope.stopFight = function() {
8348                if (angular.isDefined(stop)) {
8349                  $interval.cancel(stop);
8350                  stop = undefined;
8351                }
8352              };
8353
8354              $scope.resetFight = function() {
8355                $scope.blood_1 = 100;
8356                $scope.blood_2 = 120;
8357              }
8358
8359              $scope.$on('$destroy', function() {
8360                // Make sure that the interval is destroyed too
8361                $scope.stopFight();
8362              });
8363            }
8364
8365            angular.module('time', [])
8366              // Register the 'myCurrentTime' directive factory method.
8367              // We inject $interval and dateFilter service since the factory method is DI.
8368              .directive('myCurrentTime', function($interval, dateFilter) {
8369                // return the directive link function. (compile function not needed)
8370                return function(scope, element, attrs) {
8371                  var format,  // date format
8372                  stopTime; // so that we can cancel the time updates
8373
8374                  // used to update the UI
8375                  function updateTime() {
8376                    element.text(dateFilter(new Date(), format));
8377                  }
8378
8379                  // watch the expression, and update the UI on change.
8380                  scope.$watch(attrs.myCurrentTime, function(value) {
8381                    format = value;
8382                    updateTime();
8383                  });
8384
8385                  stopTime = $interval(updateTime, 1000);
8386
8387                  // listen on DOM destroy (removal) event, and cancel the next UI update
8388                  // to prevent updating time ofter the DOM element was removed.
8389                  element.bind('$destroy', function() {
8390                    $interval.cancel(stopTime);
8391                  });
8392                }
8393              });
8394          </script>
8395
8396          <div>
8397            <div ng-controller="Ctrl2">
8398              Date format: <input ng-model="format"> <hr/>
8399              Current time is: <span my-current-time="format"></span>
8400              <hr/>
8401              Blood 1 : <font color='red'>{{blood_1}}</font>
8402              Blood 2 : <font color='red'>{{blood_2}}</font>
8403              <button type="button" data-ng-click="fight()">Fight</button>
8404              <button type="button" data-ng-click="stopFight()">StopFight</button>
8405              <button type="button" data-ng-click="resetFight()">resetFight</button>
8406            </div>
8407          </div>
8408
8409        </doc:source>
8410      </doc:example>
8411      */
8412    function interval(fn, delay, count, invokeApply) {
8413      var setInterval = $window.setInterval,
8414          clearInterval = $window.clearInterval,
8415          deferred = $q.defer(),
8416          promise = deferred.promise,
8417          iteration = 0,
8418          skipApply = (isDefined(invokeApply) && !invokeApply);
8419
8420      count = isDefined(count) ? count : 0;
8421
8422      promise.then(null, null, fn);
8423
8424      promise.$$intervalId = setInterval(function tick() {
8425        deferred.notify(iteration++);
8426
8427        if (count > 0 && iteration >= count) {
8428          deferred.resolve(iteration);
8429          clearInterval(promise.$$intervalId);
8430          delete intervals[promise.$$intervalId];
8431        }
8432
8433        if (!skipApply) $rootScope.$apply();
8434
8435      }, delay);
8436
8437      intervals[promise.$$intervalId] = deferred;
8438
8439      return promise;
8440    }
8441
8442
8443     /**
8444      * @ngdoc function
8445      * @name ng.$interval#cancel
8446      * @methodOf ng.$interval
8447      *
8448      * @description
8449      * Cancels a task associated with the `promise`.
8450      *
8451      * @param {number} promise Promise returned by the `$interval` function.
8452      * @returns {boolean} Returns `true` if the task was successfully canceled.
8453      */
8454    interval.cancel = function(promise) {
8455      if (promise && promise.$$intervalId in intervals) {
8456        intervals[promise.$$intervalId].reject('canceled');
8457        clearInterval(promise.$$intervalId);
8458        delete intervals[promise.$$intervalId];
8459        return true;
8460      }
8461      return false;
8462    };
8463
8464    return interval;
8465  }];
8466}
8467
8468/**
8469 * @ngdoc object
8470 * @name ng.$locale
8471 *
8472 * @description
8473 * $locale service provides localization rules for various Angular components. As of right now the
8474 * only public api is:
8475 *
8476 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
8477 */
8478function $LocaleProvider(){
8479  this.$get = function() {
8480    return {
8481      id: 'en-us',
8482
8483      NUMBER_FORMATS: {
8484        DECIMAL_SEP: '.',
8485        GROUP_SEP: ',',
8486        PATTERNS: [
8487          { // Decimal Pattern
8488            minInt: 1,
8489            minFrac: 0,
8490            maxFrac: 3,
8491            posPre: '',
8492            posSuf: '',
8493            negPre: '-',
8494            negSuf: '',
8495            gSize: 3,
8496            lgSize: 3
8497          },{ //Currency Pattern
8498            minInt: 1,
8499            minFrac: 2,
8500            maxFrac: 2,
8501            posPre: '\u00A4',
8502            posSuf: '',
8503            negPre: '(\u00A4',
8504            negSuf: ')',
8505            gSize: 3,
8506            lgSize: 3
8507          }
8508        ],
8509        CURRENCY_SYM: '$'
8510      },
8511
8512      DATETIME_FORMATS: {
8513        MONTH:
8514            'January,February,March,April,May,June,July,August,September,October,November,December'
8515            .split(','),
8516        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
8517        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
8518        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
8519        AMPMS: ['AM','PM'],
8520        medium: 'MMM d, y h:mm:ss a',
8521        short: 'M/d/yy h:mm a',
8522        fullDate: 'EEEE, MMMM d, y',
8523        longDate: 'MMMM d, y',
8524        mediumDate: 'MMM d, y',
8525        shortDate: 'M/d/yy',
8526        mediumTime: 'h:mm:ss a',
8527        shortTime: 'h:mm a'
8528      },
8529
8530      pluralCat: function(num) {
8531        if (num === 1) {
8532          return 'one';
8533        }
8534        return 'other';
8535      }
8536    };
8537  };
8538}
8539
8540var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
8541    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
8542var $locationMinErr = minErr('$location');
8543
8544
8545/**
8546 * Encode path using encodeUriSegment, ignoring forward slashes
8547 *
8548 * @param {string} path Path to encode
8549 * @returns {string}
8550 */
8551function encodePath(path) {
8552  var segments = path.split('/'),
8553      i = segments.length;
8554
8555  while (i--) {
8556    segments[i] = encodeUriSegment(segments[i]);
8557  }
8558
8559  return segments.join('/');
8560}
8561
8562function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
8563  var parsedUrl = urlResolve(absoluteUrl, appBase);
8564
8565  locationObj.$$protocol = parsedUrl.protocol;
8566  locationObj.$$host = parsedUrl.hostname;
8567  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
8568}
8569
8570
8571function parseAppUrl(relativeUrl, locationObj, appBase) {
8572  var prefixed = (relativeUrl.charAt(0) !== '/');
8573  if (prefixed) {
8574    relativeUrl = '/' + relativeUrl;
8575  }
8576  var match = urlResolve(relativeUrl, appBase);
8577  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
8578      match.pathname.substring(1) : match.pathname);
8579  locationObj.$$search = parseKeyValue(match.search);
8580  locationObj.$$hash = decodeURIComponent(match.hash);
8581
8582  // make sure path starts with '/';
8583  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
8584    locationObj.$$path = '/' + locationObj.$$path;
8585  }
8586}
8587
8588
8589/**
8590 *
8591 * @param {string} begin
8592 * @param {string} whole
8593 * @returns {string} returns text from whole after begin or undefined if it does not begin with
8594 *                   expected string.
8595 */
8596function beginsWith(begin, whole) {
8597  if (whole.indexOf(begin) === 0) {
8598    return whole.substr(begin.length);
8599  }
8600}
8601
8602
8603function stripHash(url) {
8604  var index = url.indexOf('#');
8605  return index == -1 ? url : url.substr(0, index);
8606}
8607
8608
8609function stripFile(url) {
8610  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
8611}
8612
8613/* return the server only (scheme://host:port) */
8614function serverBase(url) {
8615  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
8616}
8617
8618
8619/**
8620 * LocationHtml5Url represents an url
8621 * This object is exposed as $location service when HTML5 mode is enabled and supported
8622 *
8623 * @constructor
8624 * @param {string} appBase application base URL
8625 * @param {string} basePrefix url path prefix
8626 */
8627function LocationHtml5Url(appBase, basePrefix) {
8628  this.$$html5 = true;
8629  basePrefix = basePrefix || '';
8630  var appBaseNoFile = stripFile(appBase);
8631  parseAbsoluteUrl(appBase, this, appBase);
8632
8633
8634  /**
8635   * Parse given html5 (regular) url string into properties
8636   * @param {string} newAbsoluteUrl HTML5 url
8637   * @private
8638   */
8639  this.$$parse = function(url) {
8640    var pathUrl = beginsWith(appBaseNoFile, url);
8641    if (!isString(pathUrl)) {
8642      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
8643          appBaseNoFile);
8644    }
8645
8646    parseAppUrl(pathUrl, this, appBase);
8647
8648    if (!this.$$path) {
8649      this.$$path = '/';
8650    }
8651
8652    this.$$compose();
8653  };
8654
8655  /**
8656   * Compose url and update `absUrl` property
8657   * @private
8658   */
8659  this.$$compose = function() {
8660    var search = toKeyValue(this.$$search),
8661        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
8662
8663    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
8664    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
8665  };
8666
8667  this.$$rewrite = function(url) {
8668    var appUrl, prevAppUrl;
8669
8670    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
8671      prevAppUrl = appUrl;
8672      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
8673        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
8674      } else {
8675        return appBase + prevAppUrl;
8676      }
8677    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
8678      return appBaseNoFile + appUrl;
8679    } else if (appBaseNoFile == url + '/') {
8680      return appBaseNoFile;
8681    }
8682  };
8683}
8684
8685
8686/**
8687 * LocationHashbangUrl represents url
8688 * This object is exposed as $location service when developer doesn't opt into html5 mode.
8689 * It also serves as the base class for html5 mode fallback on legacy browsers.
8690 *
8691 * @constructor
8692 * @param {string} appBase application base URL
8693 * @param {string} hashPrefix hashbang prefix
8694 */
8695function LocationHashbangUrl(appBase, hashPrefix) {
8696  var appBaseNoFile = stripFile(appBase);
8697
8698  parseAbsoluteUrl(appBase, this, appBase);
8699
8700
8701  /**
8702   * Parse given hashbang url into properties
8703   * @param {string} url Hashbang url
8704   * @private
8705   */
8706  this.$$parse = function(url) {
8707    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
8708    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
8709        ? beginsWith(hashPrefix, withoutBaseUrl)
8710        : (this.$$html5)
8711          ? withoutBaseUrl
8712          : '';
8713
8714    if (!isString(withoutHashUrl)) {
8715      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
8716          hashPrefix);
8717    }
8718    parseAppUrl(withoutHashUrl, this, appBase);
8719
8720    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
8721
8722    this.$$compose();
8723
8724    /*
8725     * In Windows, on an anchor node on documents loaded from
8726     * the filesystem, the browser will return a pathname
8727     * prefixed with the drive name ('/C:/path') when a
8728     * pathname without a drive is set:
8729     *  * a.setAttribute('href', '/foo')
8730     *   * a.pathname === '/C:/foo' //true
8731     *
8732     * Inside of Angular, we're always using pathnames that
8733     * do not include drive names for routing.
8734     */
8735    function removeWindowsDriveName (path, url, base) {
8736      /*
8737      Matches paths for file protocol on windows,
8738      such as /C:/foo/bar, and captures only /foo/bar.
8739      */
8740      var windowsFilePathExp = /^\/?.*?:(\/.*)/;
8741
8742      var firstPathSegmentMatch;
8743
8744      //Get the relative path from the input URL.
8745      if (url.indexOf(base) === 0) {
8746        url = url.replace(base, '');
8747      }
8748
8749      /*
8750       * The input URL intentionally contains a
8751       * first path segment that ends with a colon.
8752       */
8753      if (windowsFilePathExp.exec(url)) {
8754        return path;
8755      }
8756
8757      firstPathSegmentMatch = windowsFilePathExp.exec(path);
8758      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
8759    }
8760  };
8761
8762  /**
8763   * Compose hashbang url and update `absUrl` property
8764   * @private
8765   */
8766  this.$$compose = function() {
8767    var search = toKeyValue(this.$$search),
8768        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
8769
8770    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
8771    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
8772  };
8773
8774  this.$$rewrite = function(url) {
8775    if(stripHash(appBase) == stripHash(url)) {
8776      return url;
8777    }
8778  };
8779}
8780
8781
8782/**
8783 * LocationHashbangUrl represents url
8784 * This object is exposed as $location service when html5 history api is enabled but the browser
8785 * does not support it.
8786 *
8787 * @constructor
8788 * @param {string} appBase application base URL
8789 * @param {string} hashPrefix hashbang prefix
8790 */
8791function LocationHashbangInHtml5Url(appBase, hashPrefix) {
8792  this.$$html5 = true;
8793  LocationHashbangUrl.apply(this, arguments);
8794
8795  var appBaseNoFile = stripFile(appBase);
8796
8797  this.$$rewrite = function(url) {
8798    var appUrl;
8799
8800    if ( appBase == stripHash(url) ) {
8801      return url;
8802    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
8803      return appBase + hashPrefix + appUrl;
8804    } else if ( appBaseNoFile === url + '/') {
8805      return appBaseNoFile;
8806    }
8807  };
8808}
8809
8810
8811LocationHashbangInHtml5Url.prototype =
8812  LocationHashbangUrl.prototype =
8813  LocationHtml5Url.prototype = {
8814
8815  /**
8816   * Are we in html5 mode?
8817   * @private
8818   */
8819  $$html5: false,
8820
8821  /**
8822   * Has any change been replacing ?
8823   * @private
8824   */
8825  $$replace: false,
8826
8827  /**
8828   * @ngdoc method
8829   * @name ng.$location#absUrl
8830   * @methodOf ng.$location
8831   *
8832   * @description
8833   * This method is getter only.
8834   *
8835   * Return full url representation with all segments encoded according to rules specified in
8836   * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
8837   *
8838   * @return {string} full url
8839   */
8840  absUrl: locationGetter('$$absUrl'),
8841
8842  /**
8843   * @ngdoc method
8844   * @name ng.$location#url
8845   * @methodOf ng.$location
8846   *
8847   * @description
8848   * This method is getter / setter.
8849   *
8850   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
8851   *
8852   * Change path, search and hash, when called with parameter and return `$location`.
8853   *
8854   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
8855   * @param {string=} replace The path that will be changed
8856   * @return {string} url
8857   */
8858  url: function(url, replace) {
8859    if (isUndefined(url))
8860      return this.$$url;
8861
8862    var match = PATH_MATCH.exec(url);
8863    if (match[1]) this.path(decodeURIComponent(match[1]));
8864    if (match[2] || match[1]) this.search(match[3] || '');
8865    this.hash(match[5] || '', replace);
8866
8867    return this;
8868  },
8869
8870  /**
8871   * @ngdoc method
8872   * @name ng.$location#protocol
8873   * @methodOf ng.$location
8874   *
8875   * @description
8876   * This method is getter only.
8877   *
8878   * Return protocol of current url.
8879   *
8880   * @return {string} protocol of current url
8881   */
8882  protocol: locationGetter('$$protocol'),
8883
8884  /**
8885   * @ngdoc method
8886   * @name ng.$location#host
8887   * @methodOf ng.$location
8888   *
8889   * @description
8890   * This method is getter only.
8891   *
8892   * Return host of current url.
8893   *
8894   * @return {string} host of current url.
8895   */
8896  host: locationGetter('$$host'),
8897
8898  /**
8899   * @ngdoc method
8900   * @name ng.$location#port
8901   * @methodOf ng.$location
8902   *
8903   * @description
8904   * This method is getter only.
8905   *
8906   * Return port of current url.
8907   *
8908   * @return {Number} port
8909   */
8910  port: locationGetter('$$port'),
8911
8912  /**
8913   * @ngdoc method
8914   * @name ng.$location#path
8915   * @methodOf ng.$location
8916   *
8917   * @description
8918   * This method is getter / setter.
8919   *
8920   * Return path of current url when called without any parameter.
8921   *
8922   * Change path when called with parameter and return `$location`.
8923   *
8924   * Note: Path should always begin with forward slash (/), this method will add the forward slash
8925   * if it is missing.
8926   *
8927   * @param {string=} path New path
8928   * @return {string} path
8929   */
8930  path: locationGetterSetter('$$path', function(path) {
8931    return path.charAt(0) == '/' ? path : '/' + path;
8932  }),
8933
8934  /**
8935   * @ngdoc method
8936   * @name ng.$location#search
8937   * @methodOf ng.$location
8938   *
8939   * @description
8940   * This method is getter / setter.
8941   *
8942   * Return search part (as object) of current url when called without any parameter.
8943   *
8944   * Change search part when called with parameter and return `$location`.
8945   *
8946   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
8947   * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
8948   * the url.
8949   *
8950   * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
8951   * single search parameter. If `paramValue` is an array, it will set the parameter as a
8952   * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
8953   *
8954   * @return {string} search
8955   */
8956  search: function(search, paramValue) {
8957    switch (arguments.length) {
8958      case 0:
8959        return this.$$search;
8960      case 1:
8961        if (isString(search)) {
8962          this.$$search = parseKeyValue(search);
8963        } else if (isObject(search)) {
8964          this.$$search = search;
8965        } else {
8966          throw $locationMinErr('isrcharg',
8967              'The first argument of the `$location#search()` call must be a string or an object.');
8968        }
8969        break;
8970      default:
8971        if (isUndefined(paramValue) || paramValue === null) {
8972          delete this.$$search[search];
8973        } else {
8974          this.$$search[search] = paramValue;
8975        }
8976    }
8977
8978    this.$$compose();
8979    return this;
8980  },
8981
8982  /**
8983   * @ngdoc method
8984   * @name ng.$location#hash
8985   * @methodOf ng.$location
8986   *
8987   * @description
8988   * This method is getter / setter.
8989   *
8990   * Return hash fragment when called without any parameter.
8991   *
8992   * Change hash fragment when called with parameter and return `$location`.
8993   *
8994   * @param {string=} hash New hash fragment
8995   * @return {string} hash
8996   */
8997  hash: locationGetterSetter('$$hash', identity),
8998
8999  /**
9000   * @ngdoc method
9001   * @name ng.$location#replace
9002   * @methodOf ng.$location
9003   *
9004   * @description
9005   * If called, all changes to $location during current `$digest` will be replacing current history
9006   * record, instead of adding new one.
9007   */
9008  replace: function() {
9009    this.$$replace = true;
9010    return this;
9011  }
9012};
9013
9014function locationGetter(property) {
9015  return function() {
9016    return this[property];
9017  };
9018}
9019
9020
9021function locationGetterSetter(property, preprocess) {
9022  return function(value) {
9023    if (isUndefined(value))
9024      return this[property];
9025
9026    this[property] = preprocess(value);
9027    this.$$compose();
9028
9029    return this;
9030  };
9031}
9032
9033
9034/**
9035 * @ngdoc object
9036 * @name ng.$location
9037 *
9038 * @requires $browser
9039 * @requires $sniffer
9040 * @requires $rootElement
9041 *
9042 * @description
9043 * The $location service parses the URL in the browser address bar (based on the
9044 * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
9045 * available to your application. Changes to the URL in the address bar are reflected into
9046 * $location service and changes to $location are reflected into the browser address bar.
9047 *
9048 * **The $location service:**
9049 *
9050 * - Exposes the current URL in the browser address bar, so you can
9051 *   - Watch and observe the URL.
9052 *   - Change the URL.
9053 * - Synchronizes the URL with the browser when the user
9054 *   - Changes the address bar.
9055 *   - Clicks the back or forward button (or clicks a History link).
9056 *   - Clicks on a link.
9057 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9058 *
9059 * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
9060 * Services: Using $location}
9061 */
9062
9063/**
9064 * @ngdoc object
9065 * @name ng.$locationProvider
9066 * @description
9067 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9068 */
9069function $LocationProvider(){
9070  var hashPrefix = '',
9071      html5Mode = false;
9072
9073  /**
9074   * @ngdoc property
9075   * @name ng.$locationProvider#hashPrefix
9076   * @methodOf ng.$locationProvider
9077   * @description
9078   * @param {string=} prefix Prefix for hash part (containing path and search)
9079   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9080   */
9081  this.hashPrefix = function(prefix) {
9082    if (isDefined(prefix)) {
9083      hashPrefix = prefix;
9084      return this;
9085    } else {
9086      return hashPrefix;
9087    }
9088  };
9089
9090  /**
9091   * @ngdoc property
9092   * @name ng.$locationProvider#html5Mode
9093   * @methodOf ng.$locationProvider
9094   * @description
9095   * @param {boolean=} mode Use HTML5 strategy if available.
9096   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9097   */
9098  this.html5Mode = function(mode) {
9099    if (isDefined(mode)) {
9100      html5Mode = mode;
9101      return this;
9102    } else {
9103      return html5Mode;
9104    }
9105  };
9106
9107  /**
9108   * @ngdoc event
9109   * @name ng.$location#$locationChangeStart
9110   * @eventOf ng.$location
9111   * @eventType broadcast on root scope
9112   * @description
9113   * Broadcasted before a URL will change. This change can be prevented by calling
9114   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9115   * details about event object. Upon successful change
9116   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9117   *
9118   * @param {Object} angularEvent Synthetic event object.
9119   * @param {string} newUrl New URL
9120   * @param {string=} oldUrl URL that was before it was changed.
9121   */
9122
9123  /**
9124   * @ngdoc event
9125   * @name ng.$location#$locationChangeSuccess
9126   * @eventOf ng.$location
9127   * @eventType broadcast on root scope
9128   * @description
9129   * Broadcasted after a URL was changed.
9130   *
9131   * @param {Object} angularEvent Synthetic event object.
9132   * @param {string} newUrl New URL
9133   * @param {string=} oldUrl URL that was before it was changed.
9134   */
9135
9136  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9137      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9138    var $location,
9139        LocationMode,
9140        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9141        initialUrl = $browser.url(),
9142        appBase;
9143
9144    if (html5Mode) {
9145      appBase = serverBase(initialUrl) + (baseHref || '/');
9146      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9147    } else {
9148      appBase = stripHash(initialUrl);
9149      LocationMode = LocationHashbangUrl;
9150    }
9151    $location = new LocationMode(appBase, '#' + hashPrefix);
9152    $location.$$parse($location.$$rewrite(initialUrl));
9153
9154    $rootElement.on('click', function(event) {
9155      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9156      // currently we open nice url link and redirect then
9157
9158      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9159
9160      var elm = jqLite(event.target);
9161
9162      // traverse the DOM up to find first A tag
9163      while (lowercase(elm[0].nodeName) !== 'a') {
9164        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9165        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9166      }
9167
9168      var absHref = elm.prop('href');
9169
9170      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9171        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9172        // an animation.
9173        absHref = urlResolve(absHref.animVal).href;
9174      }
9175
9176      var rewrittenUrl = $location.$$rewrite(absHref);
9177
9178      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9179        event.preventDefault();
9180        if (rewrittenUrl != $browser.url()) {
9181          // update location manually
9182          $location.$$parse(rewrittenUrl);
9183          $rootScope.$apply();
9184          // hack to work around FF6 bug 684208 when scenario runner clicks on links
9185          window.angular['ff-684208-preventDefault'] = true;
9186        }
9187      }
9188    });
9189
9190
9191    // rewrite hashbang url <> html5 url
9192    if ($location.absUrl() != initialUrl) {
9193      $browser.url($location.absUrl(), true);
9194    }
9195
9196    // update $location when $browser url changes
9197    $browser.onUrlChange(function(newUrl) {
9198      if ($location.absUrl() != newUrl) {
9199        $rootScope.$evalAsync(function() {
9200          var oldUrl = $location.absUrl();
9201
9202          $location.$$parse(newUrl);
9203          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9204                                    oldUrl).defaultPrevented) {
9205            $location.$$parse(oldUrl);
9206            $browser.url(oldUrl);
9207          } else {
9208            afterLocationChange(oldUrl);
9209          }
9210        });
9211        if (!$rootScope.$$phase) $rootScope.$digest();
9212      }
9213    });
9214
9215    // update browser
9216    var changeCounter = 0;
9217    $rootScope.$watch(function $locationWatch() {
9218      var oldUrl = $browser.url();
9219      var currentReplace = $location.$$replace;
9220
9221      if (!changeCounter || oldUrl != $location.absUrl()) {
9222        changeCounter++;
9223        $rootScope.$evalAsync(function() {
9224          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9225              defaultPrevented) {
9226            $location.$$parse(oldUrl);
9227          } else {
9228            $browser.url($location.absUrl(), currentReplace);
9229            afterLocationChange(oldUrl);
9230          }
9231        });
9232      }
9233      $location.$$replace = false;
9234
9235      return changeCounter;
9236    });
9237
9238    return $location;
9239
9240    function afterLocationChange(oldUrl) {
9241      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9242    }
9243}];
9244}
9245
9246/**
9247 * @ngdoc object
9248 * @name ng.$log
9249 * @requires $window
9250 *
9251 * @description
9252 * Simple service for logging. Default implementation safely writes the message
9253 * into the browser's console (if present).
9254 * 
9255 * The main purpose of this service is to simplify debugging and troubleshooting.
9256 *
9257 * The default is to log `debug` messages. You can use
9258 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9259 *
9260 * @example
9261   <example>
9262     <file name="script.js">
9263       function LogCtrl($scope, $log) {
9264         $scope.$log = $log;
9265         $scope.message = 'Hello World!';
9266       }
9267     </file>
9268     <file name="index.html">
9269       <div ng-controller="LogCtrl">
9270         <p>Reload this page with open console, enter text and hit the log button...</p>
9271         Message:
9272         <input type="text" ng-model="message"/>
9273         <button ng-click="$log.log(message)">log</button>
9274         <button ng-click="$log.warn(message)">warn</button>
9275         <button ng-click="$log.info(message)">info</button>
9276         <button ng-click="$log.error(message)">error</button>
9277       </div>
9278     </file>
9279   </example>
9280 */
9281
9282/**
9283 * @ngdoc object
9284 * @name ng.$logProvider
9285 * @description
9286 * Use the `$logProvider` to configure how the application logs messages
9287 */
9288function $LogProvider(){
9289  var debug = true,
9290      self = this;
9291  
9292  /**
9293   * @ngdoc property
9294   * @name ng.$logProvider#debugEnabled
9295   * @methodOf ng.$logProvider
9296   * @description
9297   * @param {string=} flag enable or disable debug level messages
9298   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9299   */
9300  this.debugEnabled = function(flag) {
9301    if (isDefined(flag)) {
9302      debug = flag;
9303    return this;
9304    } else {
9305      return debug;
9306    }
9307  };
9308  
9309  this.$get = ['$window', function($window){
9310    return {
9311      /**
9312       * @ngdoc method
9313       * @name ng.$log#log
9314       * @methodOf ng.$log
9315       *
9316       * @description
9317       * Write a log message
9318       */
9319      log: consoleLog('log'),
9320
9321      /**
9322       * @ngdoc method
9323       * @name ng.$log#info
9324       * @methodOf ng.$log
9325       *
9326       * @description
9327       * Write an information message
9328       */
9329      info: consoleLog('info'),
9330
9331      /**
9332       * @ngdoc method
9333       * @name ng.$log#warn
9334       * @methodOf ng.$log
9335       *
9336       * @description
9337       * Write a warning message
9338       */
9339      warn: consoleLog('warn'),
9340
9341      /**
9342       * @ngdoc method
9343       * @name ng.$log#error
9344       * @methodOf ng.$log
9345       *
9346       * @description
9347       * Write an error message
9348       */
9349      error: consoleLog('error'),
9350      
9351      /**
9352       * @ngdoc method
9353       * @name ng.$log#debug
9354       * @methodOf ng.$log
9355       * 
9356       * @description
9357       * Write a debug message
9358       */
9359      debug: (function () {
9360        var fn = consoleLog('debug');
9361
9362        return function() {
9363          if (debug) {
9364            fn.apply(self, arguments);
9365          }
9366        };
9367      }())
9368    };
9369
9370    function formatError(arg) {
9371      if (arg instanceof Error) {
9372        if (arg.stack) {
9373          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
9374              ? 'Error: ' + arg.message + '\n' + arg.stack
9375              : arg.stack;
9376        } else if (arg.sourceURL) {
9377          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
9378        }
9379      }
9380      return arg;
9381    }
9382
9383    function consoleLog(type) {
9384      var console = $window.console || {},
9385          logFn = console[type] || console.log || noop,
9386          hasApply = false;
9387
9388      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
9389      // The reason behind this is that console.log has type "object" in IE8...
9390      try {
9391        hasApply = !! logFn.apply;
9392      } catch (e) {}
9393
9394      if (hasApply) {
9395        return function() {
9396          var args = [];
9397          forEach(arguments, function(arg) {
9398            args.push(formatError(arg));
9399          });
9400          return logFn.apply(console, args);
9401        };
9402      }
9403
9404      // we are IE which either doesn't have window.console => this is noop and we do nothing,
9405      // or we are IE where console.log doesn't have apply so we log at least first 2 args
9406      return function(arg1, arg2) {
9407        logFn(arg1, arg2 == null ? '' : arg2);
9408      };
9409    }
9410  }];
9411}
9412
9413var $parseMinErr = minErr('$parse');
9414var promiseWarningCache = {};
9415var promiseWarning;
9416
9417// Sandboxing Angular Expressions
9418// ------------------------------
9419// Angular expressions are generally considered safe because these expressions only have direct
9420// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9421// obtaining a reference to native JS functions such as the Function constructor.
9422//
9423// As an example, consider the following Angular expression:
9424//
9425//   {}.toString.constructor(alert("evil JS code"))
9426//
9427// We want to prevent this type of access. For the sake of performance, during the lexing phase we
9428// disallow any "dotted" access to any member named "constructor".
9429//
9430// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
9431// while evaluating the expression, which is a stronger but more expensive test. Since reflective
9432// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
9433//
9434// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9435// against the expression language, but not to prevent exploits that were enabled by exposing
9436// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
9437// practice and therefore we are not even trying to protect against interaction with an object
9438// explicitly exposed in this way.
9439//
9440// A developer could foil the name check by aliasing the Function constructor under a different
9441// name on the scope.
9442//
9443// In general, it is not possible to access a Window object from an angular expression unless a
9444// window or some DOM object that has a reference to window is published onto a Scope.
9445
9446function ensureSafeMemberName(name, fullExpression) {
9447  if (name === "constructor") {
9448    throw $parseMinErr('isecfld',
9449        'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
9450        fullExpression);
9451  }
9452  return name;
9453}
9454
9455function ensureSafeObject(obj, fullExpression) {
9456  // nifty check if obj is Function that is fast and works across iframes and other contexts
9457  if (obj) {
9458    if (obj.constructor === obj) {
9459      throw $parseMinErr('isecfn',
9460          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9461          fullExpression);
9462    } else if (// isWindow(obj)
9463        obj.document && obj.location && obj.alert && obj.setInterval) {
9464      throw $parseMinErr('isecwindow',
9465          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9466          fullExpression);
9467    } else if (// isElement(obj)
9468        obj.children && (obj.nodeName || (obj.on && obj.find))) {
9469      throw $parseMinErr('isecdom',
9470          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9471          fullExpression);
9472    }
9473  }
9474  return obj;
9475}
9476
9477var OPERATORS = {
9478    /* jshint bitwise : false */
9479    'null':function(){return null;},
9480    'true':function(){return true;},
9481    'false':function(){return false;},
9482    undefined:noop,
9483    '+':function(self, locals, a,b){
9484      a=a(self, locals); b=b(self, locals);
9485      if (isDefined(a)) {
9486        if (isDefined(b)) {
9487          return a + b;
9488        }
9489        return a;
9490      }
9491      return isDefined(b)?b:undefined;},
9492    '-':function(self, locals, a,b){
9493          a=a(self, locals); b=b(self, locals);
9494          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
9495        },
9496    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
9497    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
9498    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
9499    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
9500    '=':noop,
9501    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
9502    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
9503    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
9504    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
9505    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
9506    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
9507    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
9508    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
9509    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
9510    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
9511    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
9512//    '|':function(self, locals, a,b){return a|b;},
9513    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
9514    '!':function(self, locals, a){return !a(self, locals);}
9515};
9516/* jshint bitwise: true */
9517var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
9518
9519
9520/////////////////////////////////////////
9521
9522
9523/**
9524 * @constructor
9525 */
9526var Lexer = function (options) {
9527  this.options = options;
9528};
9529
9530Lexer.prototype = {
9531  constructor: Lexer,
9532
9533  lex: function (text) {
9534    this.text = text;
9535
9536    this.index = 0;
9537    this.ch = undefined;
9538    this.lastCh = ':'; // can start regexp
9539
9540    this.tokens = [];
9541
9542    var token;
9543    var json = [];
9544
9545    while (this.index < this.text.length) {
9546      this.ch = this.text.charAt(this.index);
9547      if (this.is('"\'')) {
9548        this.readString(this.ch);
9549      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
9550        this.readNumber();
9551      } else if (this.isIdent(this.ch)) {
9552        this.readIdent();
9553        // identifiers can only be if the preceding char was a { or ,
9554        if (this.was('{,') && json[0] === '{' &&
9555            (token = this.tokens[this.tokens.length - 1])) {
9556          token.json = token.text.indexOf('.') === -1;
9557        }
9558      } else if (this.is('(){}[].,;:?')) {
9559        this.tokens.push({
9560          index: this.index,
9561          text: this.ch,
9562          json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
9563        });
9564        if (this.is('{[')) json.unshift(this.ch);
9565        if (this.is('}]')) json.shift();
9566        this.index++;
9567      } else if (this.isWhitespace(this.ch)) {
9568        this.index++;
9569        continue;
9570      } else {
9571        var ch2 = this.ch + this.peek();
9572        var ch3 = ch2 + this.peek(2);
9573        var fn = OPERATORS[this.ch];
9574        var fn2 = OPERATORS[ch2];
9575        var fn3 = OPERATORS[ch3];
9576        if (fn3) {
9577          this.tokens.push({index: this.index, text: ch3, fn: fn3});
9578          this.index += 3;
9579        } else if (fn2) {
9580          this.tokens.push({index: this.index, text: ch2, fn: fn2});
9581          this.index += 2;
9582        } else if (fn) {
9583          this.tokens.push({
9584            index: this.index,
9585            text: this.ch,
9586            fn: fn,
9587            json: (this.was('[,:') && this.is('+-'))
9588          });
9589          this.index += 1;
9590        } else {
9591          this.throwError('Unexpected next character ', this.index, this.index + 1);
9592        }
9593      }
9594      this.lastCh = this.ch;
9595    }
9596    return this.tokens;
9597  },
9598
9599  is: function(chars) {
9600    return chars.indexOf(this.ch) !== -1;
9601  },
9602
9603  was: function(chars) {
9604    return chars.indexOf(this.lastCh) !== -1;
9605  },
9606
9607  peek: function(i) {
9608    var num = i || 1;
9609    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
9610  },
9611
9612  isNumber: function(ch) {
9613    return ('0' <= ch && ch <= '9');
9614  },
9615
9616  isWhitespace: function(ch) {
9617    // IE treats non-breaking space as \u00A0
9618    return (ch === ' ' || ch === '\r' || ch === '\t' ||
9619            ch === '\n' || ch === '\v' || ch === '\u00A0');
9620  },
9621
9622  isIdent: function(ch) {
9623    return ('a' <= ch && ch <= 'z' ||
9624            'A' <= ch && ch <= 'Z' ||
9625            '_' === ch || ch === '$');
9626  },
9627
9628  isExpOperator: function(ch) {
9629    return (ch === '-' || ch === '+' || this.isNumber(ch));
9630  },
9631
9632  throwError: function(error, start, end) {
9633    end = end || this.index;
9634    var colStr = (isDefined(start)
9635            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
9636            : ' ' + end);
9637    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
9638        error, colStr, this.text);
9639  },
9640
9641  readNumber: function() {
9642    var number = '';
9643    var start = this.index;
9644    while (this.index < this.text.length) {
9645      var ch = lowercase(this.text.charAt(this.index));
9646      if (ch == '.' || this.isNumber(ch)) {
9647        number += ch;
9648      } else {
9649        var peekCh = this.peek();
9650        if (ch == 'e' && this.isExpOperator(peekCh)) {
9651          number += ch;
9652        } else if (this.isExpOperator(ch) &&
9653            peekCh && this.isNumber(peekCh) &&
9654            number.charAt(number.length - 1) == 'e') {
9655          number += ch;
9656        } else if (this.isExpOperator(ch) &&
9657            (!peekCh || !this.isNumber(peekCh)) &&
9658            number.charAt(number.length - 1) == 'e') {
9659          this.throwError('Invalid exponent');
9660        } else {
9661          break;
9662        }
9663      }
9664      this.index++;
9665    }
9666    number = 1 * number;
9667    this.tokens.push({
9668      index: start,
9669      text: number,
9670      json: true,
9671      fn: function() { return number; }
9672    });
9673  },
9674
9675  readIdent: function() {
9676    var parser = this;
9677
9678    var ident = '';
9679    var start = this.index;
9680
9681    var lastDot, peekIndex, methodName, ch;
9682
9683    while (this.index < this.text.length) {
9684      ch = this.text.charAt(this.index);
9685      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
9686        if (ch === '.') lastDot = this.index;
9687        ident += ch;
9688      } else {
9689        break;
9690      }
9691      this.index++;
9692    }
9693
9694    //check if this is not a method invocation and if it is back out to last dot
9695    if (lastDot) {
9696      peekIndex = this.index;
9697      while (peekIndex < this.text.length) {
9698        ch = this.text.charAt(peekIndex);
9699        if (ch === '(') {
9700          methodName = ident.substr(lastDot - start + 1);
9701          ident = ident.substr(0, lastDot - start);
9702          this.index = peekIndex;
9703          break;
9704        }
9705        if (this.isWhitespace(ch)) {
9706          peekIndex++;
9707        } else {
9708          break;
9709        }
9710      }
9711    }
9712
9713
9714    var token = {
9715      index: start,
9716      text: ident
9717    };
9718
9719    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
9720    if (OPERATORS.hasOwnProperty(ident)) {
9721      token.fn = OPERATORS[ident];
9722      token.json = OPERATORS[ident];
9723    } else {
9724      var getter = getterFn(ident, this.options, this.text);
9725      token.fn = extend(function(self, locals) {
9726        return (getter(self, locals));
9727      }, {
9728        assign: function(self, value) {
9729          return setter(self, ident, value, parser.text, parser.options);
9730        }
9731      });
9732    }
9733
9734    this.tokens.push(token);
9735
9736    if (methodName) {
9737      this.tokens.push({
9738        index:lastDot,
9739        text: '.',
9740        json: false
9741      });
9742      this.tokens.push({
9743        index: lastDot + 1,
9744        text: methodName,
9745        json: false
9746      });
9747    }
9748  },
9749
9750  readString: function(quote) {
9751    var start = this.index;
9752    this.index++;
9753    var string = '';
9754    var rawString = quote;
9755    var escape = false;
9756    while (this.index < this.text.length) {
9757      var ch = this.text.charAt(this.index);
9758      rawString += ch;
9759      if (escape) {
9760        if (ch === 'u') {
9761          var hex = this.text.substring(this.index + 1, this.index + 5);
9762          if (!hex.match(/[\da-f]{4}/i))
9763            this.throwError('Invalid unicode escape [\\u' + hex + ']');
9764          this.index += 4;
9765          string += String.fromCharCode(parseInt(hex, 16));
9766        } else {
9767          var rep = ESCAPE[ch];
9768          if (rep) {
9769            string += rep;
9770          } else {
9771            string += ch;
9772          }
9773        }
9774        escape = false;
9775      } else if (ch === '\\') {
9776        escape = true;
9777      } else if (ch === quote) {
9778        this.index++;
9779        this.tokens.push({
9780          index: start,
9781          text: rawString,
9782          string: string,
9783          json: true,
9784          fn: function() { return string; }
9785        });
9786        return;
9787      } else {
9788        string += ch;
9789      }
9790      this.index++;
9791    }
9792    this.throwError('Unterminated quote', start);
9793  }
9794};
9795
9796
9797/**
9798 * @constructor
9799 */
9800var Parser = function (lexer, $filter, options) {
9801  this.lexer = lexer;
9802  this.$filter = $filter;
9803  this.options = options;
9804};
9805
9806Parser.ZERO = function () { return 0; };
9807
9808Parser.prototype = {
9809  constructor: Parser,
9810
9811  parse: function (text, json) {
9812    this.text = text;
9813
9814    //TODO(i): strip all the obsolte json stuff from this file
9815    this.json = json;
9816
9817    this.tokens = this.lexer.lex(text);
9818
9819    if (json) {
9820      // The extra level of aliasing is here, just in case the lexer misses something, so that
9821      // we prevent any accidental execution in JSON.
9822      this.assignment = this.logicalOR;
9823
9824      this.functionCall =
9825      this.fieldAccess =
9826      this.objectIndex =
9827      this.filterChain = function() {
9828        this.throwError('is not valid json', {text: text, index: 0});
9829      };
9830    }
9831
9832    var value = json ? this.primary() : this.statements();
9833
9834    if (this.tokens.length !== 0) {
9835      this.throwError('is an unexpected token', this.tokens[0]);
9836    }
9837
9838    value.literal = !!value.literal;
9839    value.constant = !!value.constant;
9840
9841    return value;
9842  },
9843
9844  primary: function () {
9845    var primary;
9846    if (this.expect('(')) {
9847      primary = this.filterChain();
9848      this.consume(')');
9849    } else if (this.expect('[')) {
9850      primary = this.arrayDeclaration();
9851    } else if (this.expect('{')) {
9852      primary = this.object();
9853    } else {
9854      var token = this.expect();
9855      primary = token.fn;
9856      if (!primary) {
9857        this.throwError('not a primary expression', token);
9858      }
9859      if (token.json) {
9860        primary.constant = true;
9861        primary.literal = true;
9862      }
9863    }
9864
9865    var next, context;
9866    while ((next = this.expect('(', '[', '.'))) {
9867      if (next.text === '(') {
9868        primary = this.functionCall(primary, context);
9869        context = null;
9870      } else if (next.text === '[') {
9871        context = primary;
9872        primary = this.objectIndex(primary);
9873      } else if (next.text === '.') {
9874        context = primary;
9875        primary = this.fieldAccess(primary);
9876      } else {
9877        this.throwError('IMPOSSIBLE');
9878      }
9879    }
9880    return primary;
9881  },
9882
9883  throwError: function(msg, token) {
9884    throw $parseMinErr('syntax',
9885        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
9886          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
9887  },
9888
9889  peekToken: function() {
9890    if (this.tokens.length === 0)
9891      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
9892    return this.tokens[0];
9893  },
9894
9895  peek: function(e1, e2, e3, e4) {
9896    if (this.tokens.length > 0) {
9897      var token = this.tokens[0];
9898      var t = token.text;
9899      if (t === e1 || t === e2 || t === e3 || t === e4 ||
9900          (!e1 && !e2 && !e3 && !e4)) {
9901        return token;
9902      }
9903    }
9904    return false;
9905  },
9906
9907  expect: function(e1, e2, e3, e4){
9908    var token = this.peek(e1, e2, e3, e4);
9909    if (token) {
9910      if (this.json && !token.json) {
9911        this.throwError('is not valid json', token);
9912      }
9913      this.tokens.shift();
9914      return token;
9915    }
9916    return false;
9917  },
9918
9919  consume: function(e1){
9920    if (!this.expect(e1)) {
9921      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
9922    }
9923  },
9924
9925  unaryFn: function(fn, right) {
9926    return extend(function(self, locals) {
9927      return fn(self, locals, right);
9928    }, {
9929      constant:right.constant
9930    });
9931  },
9932
9933  ternaryFn: function(left, middle, right){
9934    return extend(function(self, locals){
9935      return left(self, locals) ? middle(self, locals) : right(self, locals);
9936    }, {
9937      constant: left.constant && middle.constant && right.constant
9938    });
9939  },
9940
9941  binaryFn: function(left, fn, right) {
9942    return extend(function(self, locals) {
9943      return fn(self, locals, left, right);
9944    }, {
9945      constant:left.constant && right.constant
9946    });
9947  },
9948
9949  statements: function() {
9950    var statements = [];
9951    while (true) {
9952      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
9953        statements.push(this.filterChain());
9954      if (!this.expect(';')) {
9955        // optimize for the common case where there is only one statement.
9956        // TODO(size): maybe we should not support multiple statements?
9957        return (statements.length === 1)
9958            ? statements[0]
9959            : function(self, locals) {
9960                var value;
9961                for (var i = 0; i < statements.length; i++) {
9962                  var statement = statements[i];
9963                  if (statement) {
9964                    value = statement(self, locals);
9965                  }
9966                }
9967                return value;
9968              };
9969      }
9970    }
9971  },
9972
9973  filterChain: function() {
9974    var left = this.expression();
9975    var token;
9976    while (true) {
9977      if ((token = this.expect('|'))) {
9978        left = this.binaryFn(left, token.fn, this.filter());
9979      } else {
9980        return left;
9981      }
9982    }
9983  },
9984
9985  filter: function() {
9986    var token = this.expect();
9987    var fn = this.$filter(token.text);
9988    var argsFn = [];
9989    while (true) {
9990      if ((token = this.expect(':'))) {
9991        argsFn.push(this.expression());
9992      } else {
9993        var fnInvoke = function(self, locals, input) {
9994          var args = [input];
9995          for (var i = 0; i < argsFn.length; i++) {
9996            args.push(argsFn[i](self, locals));
9997          }
9998          return fn.apply(self, args);
9999        };
10000        return function() {
10001          return fnInvoke;
10002        };
10003      }
10004    }
10005  },
10006
10007  expression: function() {
10008    return this.assignment();
10009  },
10010
10011  assignment: function() {
10012    var left = this.ternary();
10013    var right;
10014    var token;
10015    if ((token = this.expect('='))) {
10016      if (!left.assign) {
10017        this.throwError('implies assignment but [' +
10018            this.text.substring(0, token.index) + '] can not be assigned to', token);
10019      }
10020      right = this.ternary();
10021      return function(scope, locals) {
10022        return left.assign(scope, right(scope, locals), locals);
10023      };
10024    }
10025    return left;
10026  },
10027
10028  ternary: function() {
10029    var left = this.logicalOR();
10030    var middle;
10031    var token;
10032    if ((token = this.expect('?'))) {
10033      middle = this.ternary();
10034      if ((token = this.expect(':'))) {
10035        return this.ternaryFn(left, middle, this.ternary());
10036      } else {
10037        this.throwError('expected :', token);
10038      }
10039    } else {
10040      return left;
10041    }
10042  },
10043
10044  logicalOR: function() {
10045    var left = this.logicalAND();
10046    var token;
10047    while (true) {
10048      if ((token = this.expect('||'))) {
10049        left = this.binaryFn(left, token.fn, this.logicalAND());
10050      } else {
10051        return left;
10052      }
10053    }
10054  },
10055
10056  logicalAND: function() {
10057    var left = this.equality();
10058    var token;
10059    if ((token = this.expect('&&'))) {
10060      left = this.binaryFn(left, token.fn, this.logicalAND());
10061    }
10062    return left;
10063  },
10064
10065  equality: function() {
10066    var left = this.relational();
10067    var token;
10068    if ((token = this.expect('==','!=','===','!=='))) {
10069      left = this.binaryFn(left, token.fn, this.equality());
10070    }
10071    return left;
10072  },
10073
10074  relational: function() {
10075    var left = this.additive();
10076    var token;
10077    if ((token = this.expect('<', '>', '<=', '>='))) {
10078      left = this.binaryFn(left, token.fn, this.relational());
10079    }
10080    return left;
10081  },
10082
10083  additive: function() {
10084    var left = this.multiplicative();
10085    var token;
10086    while ((token = this.expect('+','-'))) {
10087      left = this.binaryFn(left, token.fn, this.multiplicative());
10088    }
10089    return left;
10090  },
10091
10092  multiplicative: function() {
10093    var left = this.unary();
10094    var token;
10095    while ((token = this.expect('*','/','%'))) {
10096      left = this.binaryFn(left, token.fn, this.unary());
10097    }
10098    return left;
10099  },
10100
10101  unary: function() {
10102    var token;
10103    if (this.expect('+')) {
10104      return this.primary();
10105    } else if ((token = this.expect('-'))) {
10106      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10107    } else if ((token = this.expect('!'))) {
10108      return this.unaryFn(token.fn, this.unary());
10109    } else {
10110      return this.primary();
10111    }
10112  },
10113
10114  fieldAccess: function(object) {
10115    var parser = this;
10116    var field = this.expect().text;
10117    var getter = getterFn(field, this.options, this.text);
10118
10119    return extend(function(scope, locals, self) {
10120      return getter(self || object(scope, locals));
10121    }, {
10122      assign: function(scope, value, locals) {
10123        return setter(object(scope, locals), field, value, parser.text, parser.options);
10124      }
10125    });
10126  },
10127
10128  objectIndex: function(obj) {
10129    var parser = this;
10130
10131    var indexFn = this.expression();
10132    this.consume(']');
10133
10134    return extend(function(self, locals) {
10135      var o = obj(self, locals),
10136          i = indexFn(self, locals),
10137          v, p;
10138
10139      if (!o) return undefined;
10140      v = ensureSafeObject(o[i], parser.text);
10141      if (v && v.then && parser.options.unwrapPromises) {
10142        p = v;
10143        if (!('$$v' in v)) {
10144          p.$$v = undefined;
10145          p.then(function(val) { p.$$v = val; });
10146        }
10147        v = v.$$v;
10148      }
10149      return v;
10150    }, {
10151      assign: function(self, value, locals) {
10152        var key = indexFn(self, locals);
10153        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10154        var safe = ensureSafeObject(obj(self, locals), parser.text);
10155        return safe[key] = value;
10156      }
10157    });
10158  },
10159
10160  functionCall: function(fn, contextGetter) {
10161    var argsFn = [];
10162    if (this.peekToken().text !== ')') {
10163      do {
10164        argsFn.push(this.expression());
10165      } while (this.expect(','));
10166    }
10167    this.consume(')');
10168
10169    var parser = this;
10170
10171    return function(scope, locals) {
10172      var args = [];
10173      var context = contextGetter ? contextGetter(scope, locals) : scope;
10174
10175      for (var i = 0; i < argsFn.length; i++) {
10176        args.push(argsFn[i](scope, locals));
10177      }
10178      var fnPtr = fn(scope, locals, context) || noop;
10179
10180      ensureSafeObject(context, parser.text);
10181      ensureSafeObject(fnPtr, parser.text);
10182
10183      // IE stupidity! (IE doesn't have apply for some native functions)
10184      var v = fnPtr.apply
10185            ? fnPtr.apply(context, args)
10186            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10187
10188      return ensureSafeObject(v, parser.text);
10189    };
10190  },
10191
10192  // This is used with json array declaration
10193  arrayDeclaration: function () {
10194    var elementFns = [];
10195    var allConstant = true;
10196    if (this.peekToken().text !== ']') {
10197      do {
10198        var elementFn = this.expression();
10199        elementFns.push(elementFn);
10200        if (!elementFn.constant) {
10201          allConstant = false;
10202        }
10203      } while (this.expect(','));
10204    }
10205    this.consume(']');
10206
10207    return extend(function(self, locals) {
10208      var array = [];
10209      for (var i = 0; i < elementFns.length; i++) {
10210        array.push(elementFns[i](self, locals));
10211      }
10212      return array;
10213    }, {
10214      literal: true,
10215      constant: allConstant
10216    });
10217  },
10218
10219  object: function () {
10220    var keyValues = [];
10221    var allConstant = true;
10222    if (this.peekToken().text !== '}') {
10223      do {
10224        var token = this.expect(),
10225        key = token.string || token.text;
10226        this.consume(':');
10227        var value = this.expression();
10228        keyValues.push({key: key, value: value});
10229        if (!value.constant) {
10230          allConstant = false;
10231        }
10232      } while (this.expect(','));
10233    }
10234    this.consume('}');
10235
10236    return extend(function(self, locals) {
10237      var object = {};
10238      for (var i = 0; i < keyValues.length; i++) {
10239        var keyValue = keyValues[i];
10240        object[keyValue.key] = keyValue.value(self, locals);
10241      }
10242      return object;
10243    }, {
10244      literal: true,
10245      constant: allConstant
10246    });
10247  }
10248};
10249
10250
10251//////////////////////////////////////////////////
10252// Parser helper functions
10253//////////////////////////////////////////////////
10254
10255function setter(obj, path, setValue, fullExp, options) {
10256  //needed?
10257  options = options || {};
10258
10259  var element = path.split('.'), key;
10260  for (var i = 0; element.length > 1; i++) {
10261    key = ensureSafeMemberName(element.shift(), fullExp);
10262    var propertyObj = obj[key];
10263    if (!propertyObj) {
10264      propertyObj = {};
10265      obj[key] = propertyObj;
10266    }
10267    obj = propertyObj;
10268    if (obj.then && options.unwrapPromises) {
10269      promiseWarning(fullExp);
10270      if (!("$$v" in obj)) {
10271        (function(promise) {
10272          promise.then(function(val) { promise.$$v = val; }); }
10273        )(obj);
10274      }
10275      if (obj.$$v === undefined) {
10276        obj.$$v = {};
10277      }
10278      obj = obj.$$v;
10279    }
10280  }
10281  key = ensureSafeMemberName(element.shift(), fullExp);
10282  obj[key] = setValue;
10283  return setValue;
10284}
10285
10286var getterFnCache = {};
10287
10288/**
10289 * Implementation of the "Black Hole" variant from:
10290 * - http://jsperf.com/angularjs-parse-getter/4
10291 * - http://jsperf.com/path-evaluation-simplified/7
10292 */
10293function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10294  ensureSafeMemberName(key0, fullExp);
10295  ensureSafeMemberName(key1, fullExp);
10296  ensureSafeMemberName(key2, fullExp);
10297  ensureSafeMemberName(key3, fullExp);
10298  ensureSafeMemberName(key4, fullExp);
10299
10300  return !options.unwrapPromises
10301      ? function cspSafeGetter(scope, locals) {
10302          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10303
10304          if (pathVal == null) return pathVal;
10305          pathVal = pathVal[key0];
10306
10307          if (!key1) return pathVal;
10308          if (pathVal == null) return undefined;
10309          pathVal = pathVal[key1];
10310
10311          if (!key2) return pathVal;
10312          if (pathVal == null) return undefined;
10313          pathVal = pathVal[key2];
10314
10315          if (!key3) return pathVal;
10316          if (pathVal == null) return undefined;
10317          pathVal = pathVal[key3];
10318
10319          if (!key4) return pathVal;
10320          if (pathVal == null) return undefined;
10321          pathVal = pathVal[key4];
10322
10323          return pathVal;
10324        }
10325      : function cspSafePromiseEnabledGetter(scope, locals) {
10326          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10327              promise;
10328
10329          if (pathVal == null) return pathVal;
10330
10331          pathVal = pathVal[key0];
10332          if (pathVal && pathVal.then) {
10333            promiseWarning(fullExp);
10334            if (!("$$v" in pathVal)) {
10335              promise = pathVal;
10336              promise.$$v = undefined;
10337              promise.then(function(val) { promise.$$v = val; });
10338            }
10339            pathVal = pathVal.$$v;
10340          }
10341
10342          if (!key1) return pathVal;
10343          if (pathVal == null) return undefined;
10344          pathVal = pathVal[key1];
10345          if (pathVal && pathVal.then) {
10346            promiseWarning(fullExp);
10347            if (!("$$v" in pathVal)) {
10348              promise = pathVal;
10349              promise.$$v = undefined;
10350              promise.then(function(val) { promise.$$v = val; });
10351            }
10352            pathVal = pathVal.$$v;
10353          }
10354
10355          if (!key2) return pathVal;
10356          if (pathVal == null) return undefined;
10357          pathVal = pathVal[key2];
10358          if (pathVal && pathVal.then) {
10359            promiseWarning(fullExp);
10360            if (!("$$v" in pathVal)) {
10361              promise = pathVal;
10362              promise.$$v = undefined;
10363              promise.then(function(val) { promise.$$v = val; });
10364            }
10365            pathVal = pathVal.$$v;
10366          }
10367
10368          if (!key3) return pathVal;
10369          if (pathVal == null) return undefined;
10370          pathVal = pathVal[key3];
10371          if (pathVal && pathVal.then) {
10372            promiseWarning(fullExp);
10373            if (!("$$v" in pathVal)) {
10374              promise = pathVal;
10375              promise.$$v = undefined;
10376              promise.then(function(val) { promise.$$v = val; });
10377            }
10378            pathVal = pathVal.$$v;
10379          }
10380
10381          if (!key4) return pathVal;
10382          if (pathVal == null) return undefined;
10383          pathVal = pathVal[key4];
10384          if (pathVal && pathVal.then) {
10385            promiseWarning(fullExp);
10386            if (!("$$v" in pathVal)) {
10387              promise = pathVal;
10388              promise.$$v = undefined;
10389              promise.then(function(val) { promise.$$v = val; });
10390            }
10391            pathVal = pathVal.$$v;
10392          }
10393          return pathVal;
10394        };
10395}
10396
10397function simpleGetterFn1(key0, fullExp) {
10398  ensureSafeMemberName(key0, fullExp);
10399
10400  return function simpleGetterFn1(scope, locals) {
10401    if (scope == null) return undefined;
10402    return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10403  };
10404}
10405
10406function simpleGetterFn2(key0, key1, fullExp) {
10407  ensureSafeMemberName(key0, fullExp);
10408  ensureSafeMemberName(key1, fullExp);
10409
10410  return function simpleGetterFn2(scope, locals) {
10411    if (scope == null) return undefined;
10412    scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10413    return scope == null ? undefined : scope[key1];
10414  };
10415}
10416
10417function getterFn(path, options, fullExp) {
10418  // Check whether the cache has this getter already.
10419  // We can use hasOwnProperty directly on the cache because we ensure,
10420  // see below, that the cache never stores a path called 'hasOwnProperty'
10421  if (getterFnCache.hasOwnProperty(path)) {
10422    return getterFnCache[path];
10423  }
10424
10425  var pathKeys = path.split('.'),
10426      pathKeysLength = pathKeys.length,
10427      fn;
10428
10429  // When we have only 1 or 2 tokens, use optimized special case closures.
10430  // http://jsperf.com/angularjs-parse-getter/6
10431  if (!options.unwrapPromises && pathKeysLength === 1) {
10432    fn = simpleGetterFn1(pathKeys[0], fullExp);
10433  } else if (!options.unwrapPromises && pathKeysLength === 2) {
10434    fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
10435  } else if (options.csp) {
10436    if (pathKeysLength < 6) {
10437      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
10438                          options);
10439    } else {
10440      fn = function(scope, locals) {
10441        var i = 0, val;
10442        do {
10443          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
10444                                pathKeys[i++], fullExp, options)(scope, locals);
10445
10446          locals = undefined; // clear after first iteration
10447          scope = val;
10448        } while (i < pathKeysLength);
10449        return val;
10450      };
10451    }
10452  } else {
10453    var code = 'var p;\n';
10454    forEach(pathKeys, function(key, index) {
10455      ensureSafeMemberName(key, fullExp);
10456      code += 'if(s == null) return undefined;\n' +
10457              's='+ (index
10458                      // we simply dereference 's' on any .dot notation
10459                      ? 's'
10460                      // but if we are first then we check locals first, and if so read it first
10461                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
10462              (options.unwrapPromises
10463                ? 'if (s && s.then) {\n' +
10464                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
10465                  ' if (!("$$v" in s)) {\n' +
10466                    ' p=s;\n' +
10467                    ' p.$$v = undefined;\n' +
10468                    ' p.then(function(v) {p.$$v=v;});\n' +
10469                    '}\n' +
10470                  ' s=s.$$v\n' +
10471                '}\n'
10472                : '');
10473    });
10474    code += 'return s;';
10475
10476    /* jshint -W054 */
10477    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
10478    /* jshint +W054 */
10479    evaledFnGetter.toString = valueFn(code);
10480    fn = options.unwrapPromises ? function(scope, locals) {
10481      return evaledFnGetter(scope, locals, promiseWarning);
10482    } : evaledFnGetter;
10483  }
10484
10485  // Only cache the value if it's not going to mess up the cache object
10486  // This is more performant that using Object.prototype.hasOwnProperty.call
10487  if (path !== 'hasOwnProperty') {
10488    getterFnCache[path] = fn;
10489  }
10490  return fn;
10491}
10492
10493///////////////////////////////////
10494
10495/**
10496 * @ngdoc function
10497 * @name ng.$parse
10498 * @function
10499 *
10500 * @description
10501 *
10502 * Converts Angular {@link guide/expression expression} into a function.
10503 *
10504 * <pre>
10505 *   var getter = $parse('user.name');
10506 *   var setter = getter.assign;
10507 *   var context = {user:{name:'angular'}};
10508 *   var locals = {user:{name:'local'}};
10509 *
10510 *   expect(getter(context)).toEqual('angular');
10511 *   setter(context, 'newValue');
10512 *   expect(context.user.name).toEqual('newValue');
10513 *   expect(getter(context, locals)).toEqual('local');
10514 * </pre>
10515 *
10516 *
10517 * @param {string} expression String expression to compile.
10518 * @returns {function(context, locals)} a function which represents the compiled expression:
10519 *
10520 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
10521 *      are evaluated against (typically a scope object).
10522 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
10523 *      `context`.
10524 *
10525 *    The returned function also has the following properties:
10526 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
10527 *        literal.
10528 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
10529 *        constant literals.
10530 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
10531 *        set to a function to change its value on the given context.
10532 *
10533 */
10534
10535
10536/**
10537 * @ngdoc object
10538 * @name ng.$parseProvider
10539 * @function
10540 *
10541 * @description
10542 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
10543 *  service.
10544 */
10545function $ParseProvider() {
10546  var cache = {};
10547
10548  var $parseOptions = {
10549    csp: false,
10550    unwrapPromises: false,
10551    logPromiseWarnings: true
10552  };
10553
10554
10555  /**
10556   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
10557   *
10558   * @ngdoc method
10559   * @name ng.$parseProvider#unwrapPromises
10560   * @methodOf ng.$parseProvider
10561   * @description
10562   *
10563   * **This feature is deprecated, see deprecation notes below for more info**
10564   *
10565   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
10566   * found at any part of the expression. In other words, if set to true, the expression will always
10567   * result in a non-promise value.
10568   *
10569   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
10570   * the fulfillment value is used in place of the promise while evaluating the expression.
10571   *
10572   * **Deprecation notice**
10573   *
10574   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
10575   * dichotomy between data access in templates (accessed as raw values) and controller code
10576   * (accessed as promises).
10577   *
10578   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
10579   * the model access there.
10580   *
10581   * Other downsides of automatic promise unwrapping:
10582   *
10583   * - when building components it's often desirable to receive the raw promises
10584   * - adds complexity and slows down expression evaluation
10585   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
10586   *   generated
10587   * - makes IDE auto-completion and tool support hard
10588   *
10589   * **Warning Logs**
10590   *
10591   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
10592   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
10593   * `$parseProvider.logPromiseWarnings(false)` api.
10594   *
10595   *
10596   * @param {boolean=} value New value.
10597   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
10598   *                         setter.
10599   */
10600  this.unwrapPromises = function(value) {
10601    if (isDefined(value)) {
10602      $parseOptions.unwrapPromises = !!value;
10603      return this;
10604    } else {
10605      return $parseOptions.unwrapPromises;
10606    }
10607  };
10608
10609
10610  /**
10611   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
10612   *
10613   * @ngdoc method
10614   * @name ng.$parseProvider#logPromiseWarnings
10615   * @methodOf ng.$parseProvider
10616   * @description
10617   *
10618   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
10619   *
10620   * The default is set to `true`.
10621   *
10622   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
10623   *
10624   * @param {boolean=} value New value.
10625   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
10626   *                         setter.
10627   */
10628 this.logPromiseWarnings = function(value) {
10629    if (isDefined(value)) {
10630      $parseOptions.logPromiseWarnings = value;
10631      return this;
10632    } else {
10633      return $parseOptions.logPromiseWarnings;
10634    }
10635  };
10636
10637
10638  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
10639    $parseOptions.csp = $sniffer.csp;
10640
10641    promiseWarning = function promiseWarningFn(fullExp) {
10642      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
10643      promiseWarningCache[fullExp] = true;
10644      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
10645          'Automatic unwrapping of promises in Angular expressions is deprecated.');
10646    };
10647
10648    return function(exp) {
10649      var parsedExpression;
10650
10651      switch (typeof exp) {
10652        case 'string':
10653
10654          if (cache.hasOwnProperty(exp)) {
10655            return cache[exp];
10656          }
10657
10658          var lexer = new Lexer($parseOptions);
10659          var parser = new Parser(lexer, $filter, $parseOptions);
10660          parsedExpression = parser.parse(exp, false);
10661
10662          if (exp !== 'hasOwnProperty') {
10663            // Only cache the value if it's not going to mess up the cache object
10664            // This is more performant that using Object.prototype.hasOwnProperty.call
10665            cache[exp] = parsedExpression;
10666          }
10667
10668          return parsedExpression;
10669
10670        case 'function':
10671          return exp;
10672
10673        default:
10674          return noop;
10675      }
10676    };
10677  }];
10678}
10679
10680/**
10681 * @ngdoc service
10682 * @name ng.$q
10683 * @requires $rootScope
10684 *
10685 * @description
10686 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
10687 *
10688 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
10689 * interface for interacting with an object that represents the result of an action that is
10690 * performed asynchronously, and may or may not be finished at any given point in time.
10691 *
10692 * From the perspective of dealing with error handling, deferred and promise APIs are to
10693 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
10694 *
10695 * <pre>
10696 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
10697 *   // are available in the current lexical scope (they could have been injected or passed in).
10698 * 
10699 *   function asyncGreet(name) {
10700 *     var deferred = $q.defer();
10701 *
10702 *     setTimeout(function() {
10703 *       // since this fn executes async in a future turn of the event loop, we need to wrap
10704 *       // our code into an $apply call so that the model changes are properly observed.
10705 *       scope.$apply(function() {
10706 *         deferred.notify('About to greet ' + name + '.');
10707 *
10708 *         if (okToGreet(name)) {
10709 *           deferred.resolve('Hello, ' + name + '!');
10710 *         } else {
10711 *           deferred.reject('Greeting ' + name + ' is not allowed.');
10712 *         }
10713 *       });
10714 *     }, 1000);
10715 *
10716 *     return deferred.promise;
10717 *   }
10718 *
10719 *   var promise = asyncGreet('Robin Hood');
10720 *   promise.then(function(greeting) {
10721 *     alert('Success: ' + greeting);
10722 *   }, function(reason) {
10723 *     alert('Failed: ' + reason);
10724 *   }, function(update) {
10725 *     alert('Got notification: ' + update);
10726 *   });
10727 * </pre>
10728 *
10729 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
10730 * comes in the way of guarantees that promise and deferred APIs make, see
10731 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
10732 *
10733 * Additionally the promise api allows for composition that is very hard to do with the
10734 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
10735 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
10736 * section on serial or parallel joining of promises.
10737 *
10738 *
10739 * # The Deferred API
10740 *
10741 * A new instance of deferred is constructed by calling `$q.defer()`.
10742 *
10743 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
10744 * that can be used for signaling the successful or unsuccessful completion, as well as the status
10745 * of the task.
10746 *
10747 * **Methods**
10748 *
10749 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
10750 *   constructed via `$q.reject`, the promise will be rejected instead.
10751 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
10752 *   resolving it with a rejection constructed via `$q.reject`.
10753 * - `notify(value)` - provides updates on the status of the promises execution. This may be called
10754 *   multiple times before the promise is either resolved or rejected.
10755 *
10756 * **Properties**
10757 *
10758 * - promise – `{Promise}` – promise object associated with this deferred.
10759 *
10760 *
10761 * # The Promise API
10762 *
10763 * A new promise instance is created when a deferred instance is created and can be retrieved by
10764 * calling `deferred.promise`.
10765 *
10766 * The purpose of the promise object is to allow for interested parties to get access to the result
10767 * of the deferred task when it completes.
10768 *
10769 * **Methods**
10770 *
10771 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
10772 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
10773 *   as soon as the result is available. The callbacks are called with a single argument: the result
10774 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
10775 *   provide a progress indication, before the promise is resolved or rejected.
10776 *
10777 *   This method *returns a new promise* which is resolved or rejected via the return value of the
10778 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
10779 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
10780 *   method.
10781 *
10782 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
10783 *
10784 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
10785 *   but to do so without modifying the final value. This is useful to release resources or do some
10786 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
10787 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
10788 *   more information.
10789 *
10790 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
10791 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
10792 *   make your code IE8 compatible.
10793 *
10794 * # Chaining promises
10795 *
10796 * Because calling the `then` method of a promise returns a new derived promise, it is easily
10797 * possible to create a chain of promises:
10798 *
10799 * <pre>
10800 *   promiseB = promiseA.then(function(result) {
10801 *     return result + 1;
10802 *   });
10803 *
10804 *   // promiseB will be resolved immediately after promiseA is resolved and its value
10805 *   // will be the result of promiseA incremented by 1
10806 * </pre>
10807 *
10808 * It is possible to create chains of any length and since a promise can be resolved with another
10809 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
10810 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
10811 * $http's response interceptors.
10812 *
10813 *
10814 * # Differences between Kris Kowal's Q and $q
10815 *
10816 *  There are two main differences:
10817 *
10818 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
10819 *   mechanism in angular, which means faster propagation of resolution or rejection into your
10820 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
10821 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
10822 *   all the important functionality needed for common async tasks.
10823 *
10824 *  # Testing
10825 *
10826 *  <pre>
10827 *    it('should simulate promise', inject(function($q, $rootScope) {
10828 *      var deferred = $q.defer();
10829 *      var promise = deferred.promise;
10830 *      var resolvedValue;
10831 *
10832 *      promise.then(function(value) { resolvedValue = value; });
10833 *      expect(resolvedValue).toBeUndefined();
10834 *
10835 *      // Simulate resolving of promise
10836 *      deferred.resolve(123);
10837 *      // Note that the 'then' function does not get called synchronously.
10838 *      // This is because we want the promise API to always be async, whether or not
10839 *      // it got called synchronously or asynchronously.
10840 *      expect(resolvedValue).toBeUndefined();
10841 *
10842 *      // Propagate promise resolution to 'then' functions using $apply().
10843 *      $rootScope.$apply();
10844 *      expect(resolvedValue).toEqual(123);
10845 *    }));
10846 *  </pre>
10847 */
10848function $QProvider() {
10849
10850  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
10851    return qFactory(function(callback) {
10852      $rootScope.$evalAsync(callback);
10853    }, $exceptionHandler);
10854  }];
10855}
10856
10857
10858/**
10859 * Constructs a promise manager.
10860 *
10861 * @param {function(function)} nextTick Function for executing functions in the next turn.
10862 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
10863 *     debugging purposes.
10864 * @returns {object} Promise manager.
10865 */
10866function qFactory(nextTick, exceptionHandler) {
10867
10868  /**
10869   * @ngdoc
10870   * @name ng.$q#defer
10871   * @methodOf ng.$q
10872   * @description
10873   * Creates a `Deferred` object which represents a task which will finish in the future.
10874   *
10875   * @returns {Deferred} Returns a new instance of deferred.
10876   */
10877  var defer = function() {
10878    var pending = [],
10879        value, deferred;
10880
10881    deferred = {
10882
10883      resolve: function(val) {
10884        if (pending) {
10885          var callbacks = pending;
10886          pending = undefined;
10887          value = ref(val);
10888
10889          if (callbacks.length) {
10890            nextTick(function() {
10891              var callback;
10892              for (var i = 0, ii = callbacks.length; i < ii; i++) {
10893                callback = callbacks[i];
10894                value.then(callback[0], callback[1], callback[2]);
10895              }
10896            });
10897          }
10898        }
10899      },
10900
10901
10902      reject: function(reason) {
10903        deferred.resolve(reject(reason));
10904      },
10905
10906
10907      notify: function(progress) {
10908        if (pending) {
10909          var callbacks = pending;
10910
10911          if (pending.length) {
10912            nextTick(function() {
10913              var callback;
10914              for (var i = 0, ii = callbacks.length; i < ii; i++) {
10915                callback = callbacks[i];
10916                callback[2](progress);
10917              }
10918            });
10919          }
10920        }
10921      },
10922
10923
10924      promise: {
10925        then: function(callback, errback, progressback) {
10926          var result = defer();
10927
10928          var wrappedCallback = function(value) {
10929            try {
10930              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
10931            } catch(e) {
10932              result.reject(e);
10933              exceptionHandler(e);
10934            }
10935          };
10936
10937          var wrappedErrback = function(reason) {
10938            try {
10939              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
10940            } catch(e) {
10941              result.reject(e);
10942              exceptionHandler(e);
10943            }
10944          };
10945
10946          var wrappedProgressback = function(progress) {
10947            try {
10948              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
10949            } catch(e) {
10950              exceptionHandler(e);
10951            }
10952          };
10953
10954          if (pending) {
10955            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
10956          } else {
10957            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
10958          }
10959
10960          return result.promise;
10961        },
10962
10963        "catch": function(callback) {
10964          return this.then(null, callback);
10965        },
10966
10967        "finally": function(callback) {
10968
10969          function makePromise(value, resolved) {
10970            var result = defer();
10971            if (resolved) {
10972              result.resolve(value);
10973            } else {
10974              result.reject(value);
10975            }
10976            return result.promise;
10977          }
10978
10979          function handleCallback(value, isResolved) {
10980            var callbackOutput = null;
10981            try {
10982              callbackOutput = (callback ||defaultCallback)();
10983            } catch(e) {
10984              return makePromise(e, false);
10985            }
10986            if (callbackOutput && isFunction(callbackOutput.then)) {
10987              return callbackOutput.then(function() {
10988                return makePromise(value, isResolved);
10989              }, function(error) {
10990                return makePromise(error, false);
10991              });
10992            } else {
10993              return makePromise(value, isResolved);
10994            }
10995          }
10996
10997          return this.then(function(value) {
10998            return handleCallback(value, true);
10999          }, function(error) {
11000            return handleCallback(error, false);
11001          });
11002        }
11003      }
11004    };
11005
11006    return deferred;
11007  };
11008
11009
11010  var ref = function(value) {
11011    if (value && isFunction(value.then)) return value;
11012    return {
11013      then: function(callback) {
11014        var result = defer();
11015        nextTick(function() {
11016          result.resolve(callback(value));
11017        });
11018        return result.promise;
11019      }
11020    };
11021  };
11022
11023
11024  /**
11025   * @ngdoc
11026   * @name ng.$q#reject
11027   * @methodOf ng.$q
11028   * @description
11029   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11030   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11031   * a promise chain, you don't need to worry about it.
11032   *
11033   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11034   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11035   * a promise error callback and you want to forward the error to the promise derived from the
11036   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11037   * `reject`.
11038   *
11039   * <pre>
11040   *   promiseB = promiseA.then(function(result) {
11041   *     // success: do something and resolve promiseB
11042   *     //          with the old or a new result
11043   *     return result;
11044   *   }, function(reason) {
11045   *     // error: handle the error if possible and
11046   *     //        resolve promiseB with newPromiseOrValue,
11047   *     //        otherwise forward the rejection to promiseB
11048   *     if (canHandle(reason)) {
11049   *      // handle the error and recover
11050   *      return newPromiseOrValue;
11051   *     }
11052   *     return $q.reject(reason);
11053   *   });
11054   * </pre>
11055   *
11056   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11057   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11058   */
11059  var reject = function(reason) {
11060    return {
11061      then: function(callback, errback) {
11062        var result = defer();
11063        nextTick(function() {
11064          try {
11065            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11066          } catch(e) {
11067            result.reject(e);
11068            exceptionHandler(e);
11069          }
11070        });
11071        return result.promise;
11072      }
11073    };
11074  };
11075
11076
11077  /**
11078   * @ngdoc
11079   * @name ng.$q#when
11080   * @methodOf ng.$q
11081   * @description
11082   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11083   * This is useful when you are dealing with an object that might or might not be a promise, or if
11084   * the promise comes from a source that can't be trusted.
11085   *
11086   * @param {*} value Value or a promise
11087   * @returns {Promise} Returns a promise of the passed value or promise
11088   */
11089  var when = function(value, callback, errback, progressback) {
11090    var result = defer(),
11091        done;
11092
11093    var wrappedCallback = function(value) {
11094      try {
11095        return (isFunction(callback) ? callback : defaultCallback)(value);
11096      } catch (e) {
11097        exceptionHandler(e);
11098        return reject(e);
11099      }
11100    };
11101
11102    var wrappedErrback = function(reason) {
11103      try {
11104        return (isFunction(errback) ? errback : defaultErrback)(reason);
11105      } catch (e) {
11106        exceptionHandler(e);
11107        return reject(e);
11108      }
11109    };
11110
11111    var wrappedProgressback = function(progress) {
11112      try {
11113        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11114      } catch (e) {
11115        exceptionHandler(e);
11116      }
11117    };
11118
11119    nextTick(function() {
11120      ref(value).then(function(value) {
11121        if (done) return;
11122        done = true;
11123        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11124      }, function(reason) {
11125        if (done) return;
11126        done = true;
11127        result.resolve(wrappedErrback(reason));
11128      }, function(progress) {
11129        if (done) return;
11130        result.notify(wrappedProgressback(progress));
11131      });
11132    });
11133
11134    return result.promise;
11135  };
11136
11137
11138  function defaultCallback(value) {
11139    return value;
11140  }
11141
11142
11143  function defaultErrback(reason) {
11144    return reject(reason);
11145  }
11146
11147
11148  /**
11149   * @ngdoc
11150   * @name ng.$q#all
11151   * @methodOf ng.$q
11152   * @description
11153   * Combines multiple promises into a single promise that is resolved when all of the input
11154   * promises are resolved.
11155   *
11156   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11157   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11158   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11159   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11160   *   with the same rejection value.
11161   */
11162  function all(promises) {
11163    var deferred = defer(),
11164        counter = 0,
11165        results = isArray(promises) ? [] : {};
11166
11167    forEach(promises, function(promise, key) {
11168      counter++;
11169      ref(promise).then(function(value) {
11170        if (results.hasOwnProperty(key)) return;
11171        results[key] = value;
11172        if (!(--counter)) deferred.resolve(results);
11173      }, function(reason) {
11174        if (results.hasOwnProperty(key)) return;
11175        deferred.reject(reason);
11176      });
11177    });
11178
11179    if (counter === 0) {
11180      deferred.resolve(results);
11181    }
11182
11183    return deferred.promise;
11184  }
11185
11186  return {
11187    defer: defer,
11188    reject: reject,
11189    when: when,
11190    all: all
11191  };
11192}
11193
11194/**
11195 * DESIGN NOTES
11196 *
11197 * The design decisions behind the scope are heavily favored for speed and memory consumption.
11198 *
11199 * The typical use of scope is to watch the expressions, which most of the time return the same
11200 * value as last time so we optimize the operation.
11201 *
11202 * Closures construction is expensive in terms of speed as well as memory:
11203 *   - No closures, instead use prototypical inheritance for API
11204 *   - Internal state needs to be stored on scope directly, which means that private state is
11205 *     exposed as $$____ properties
11206 *
11207 * Loop operations are optimized by using while(count--) { ... }
11208 *   - this means that in order to keep the same order of execution as addition we have to add
11209 *     items to the array at the beginning (shift) instead of at the end (push)
11210 *
11211 * Child scopes are created and removed often
11212 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11213 *
11214 * There are few watches then a lot of observers. This is why you don't want the observer to be
11215 * implemented in the same way as watch. Watch requires return of initialization function which
11216 * are expensive to construct.
11217 */
11218
11219
11220/**
11221 * @ngdoc object
11222 * @name ng.$rootScopeProvider
11223 * @description
11224 *
11225 * Provider for the $rootScope service.
11226 */
11227
11228/**
11229 * @ngdoc function
11230 * @name ng.$rootScopeProvider#digestTtl
11231 * @methodOf ng.$rootScopeProvider
11232 * @description
11233 *
11234 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11235 * assuming that the model is unstable.
11236 *
11237 * The current default is 10 iterations.
11238 *
11239 * In complex applications it's possible that the dependencies between `$watch`s will result in
11240 * several digest iterations. However if an application needs more than the default 10 digest
11241 * iterations for its model to stabilize then you should investigate what is causing the model to
11242 * continuously change during the digest.
11243 *
11244 * Increasing the TTL could have performance implications, so you should not change it without
11245 * proper justification.
11246 *
11247 * @param {number} limit The number of digest iterations.
11248 */
11249
11250
11251/**
11252 * @ngdoc object
11253 * @name ng.$rootScope
11254 * @description
11255 *
11256 * Every application has a single root {@link ng.$rootScope.Scope scope}.
11257 * All other scopes are descendant scopes of the root scope. Scopes provide separation
11258 * between the model and the view, via a mechanism for watching the model for changes.
11259 * They also provide an event emission/broadcast and subscription facility. See the
11260 * {@link guide/scope developer guide on scopes}.
11261 */
11262function $RootScopeProvider(){
11263  var TTL = 10;
11264  var $rootScopeMinErr = minErr('$rootScope');
11265  var lastDirtyWatch = null;
11266
11267  this.digestTtl = function(value) {
11268    if (arguments.length) {
11269      TTL = value;
11270    }
11271    return TTL;
11272  };
11273
11274  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11275      function( $injector,   $exceptionHandler,   $parse,   $browser) {
11276
11277    /**
11278     * @ngdoc function
11279     * @name ng.$rootScope.Scope
11280     *
11281     * @description
11282     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11283     * {@link AUTO.$injector $injector}. Child scopes are created using the
11284     * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when
11285     * compiled HTML template is executed.)
11286     *
11287     * Here is a simple scope snippet to show how you can interact with the scope.
11288     * <pre>
11289     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11290     * </pre>
11291     *
11292     * # Inheritance
11293     * A scope can inherit from a parent scope, as in this example:
11294     * <pre>
11295         var parent = $rootScope;
11296         var child = parent.$new();
11297
11298         parent.salutation = "Hello";
11299         child.name = "World";
11300         expect(child.salutation).toEqual('Hello');
11301
11302         child.salutation = "Welcome";
11303         expect(child.salutation).toEqual('Welcome');
11304         expect(parent.salutation).toEqual('Hello');
11305     * </pre>
11306     *
11307     *
11308     * @param {Object.<string, function()>=} providers Map of service factory which need to be
11309     *                                       provided for the current scope. Defaults to {@link ng}.
11310     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11311     *                              append/override services provided by `providers`. This is handy
11312     *                              when unit-testing and having the need to override a default
11313     *                              service.
11314     * @returns {Object} Newly created scope.
11315     *
11316     */
11317    function Scope() {
11318      this.$id = nextUid();
11319      this.$$phase = this.$parent = this.$$watchers =
11320                     this.$$nextSibling = this.$$prevSibling =
11321                     this.$$childHead = this.$$childTail = null;
11322      this['this'] = this.$root =  this;
11323      this.$$destroyed = false;
11324      this.$$asyncQueue = [];
11325      this.$$postDigestQueue = [];
11326      this.$$listeners = {};
11327      this.$$listenerCount = {};
11328      this.$$isolateBindings = {};
11329    }
11330
11331    /**
11332     * @ngdoc property
11333     * @name ng.$rootScope.Scope#$id
11334     * @propertyOf ng.$rootScope.Scope
11335     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11336     *   debugging.
11337     */
11338
11339
11340    Scope.prototype = {
11341      constructor: Scope,
11342      /**
11343       * @ngdoc function
11344       * @name ng.$rootScope.Scope#$new
11345       * @methodOf ng.$rootScope.Scope
11346       * @function
11347       *
11348       * @description
11349       * Creates a new child {@link ng.$rootScope.Scope scope}.
11350       *
11351       * The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and
11352       * {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the
11353       * scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}.
11354       *
11355       * {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is
11356       * desired for the scope and its child scopes to be permanently detached from the parent and
11357       * thus stop participating in model change detection and listener notification by invoking.
11358       *
11359       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
11360       *         parent scope. The scope is isolated, as it can not see parent scope properties.
11361       *         When creating widgets, it is useful for the widget to not accidentally read parent
11362       *         state.
11363       *
11364       * @returns {Object} The newly created child scope.
11365       *
11366       */
11367      $new: function(isolate) {
11368        var ChildScope,
11369            child;
11370
11371        if (isolate) {
11372          child = new Scope();
11373          child.$root = this.$root;
11374          // ensure that there is just one async queue per $rootScope and its children
11375          child.$$asyncQueue = this.$$asyncQueue;
11376          child.$$postDigestQueue = this.$$postDigestQueue;
11377        } else {
11378          ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
11379            // the name it does not become random set of chars. This will then show up as class
11380            // name in the web inspector.
11381          ChildScope.prototype = this;
11382          child = new ChildScope();
11383          child.$id = nextUid();
11384        }
11385        child['this'] = child;
11386        child.$$listeners = {};
11387        child.$$listenerCount = {};
11388        child.$parent = this;
11389        child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
11390        child.$$prevSibling = this.$$childTail;
11391        if (this.$$childHead) {
11392          this.$$childTail.$$nextSibling = child;
11393          this.$$childTail = child;
11394        } else {
11395          this.$$childHead = this.$$childTail = child;
11396        }
11397        return child;
11398      },
11399
11400      /**
11401       * @ngdoc function
11402       * @name ng.$rootScope.Scope#$watch
11403       * @methodOf ng.$rootScope.Scope
11404       * @function
11405       *
11406       * @description
11407       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
11408       *
11409       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest
11410       *   $digest()} and should return the value that will be watched. (Since
11411       *   {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the
11412       *   `watchExpression` can execute multiple times per
11413       *   {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.)
11414       * - The `listener` is called only when the value from the current `watchExpression` and the
11415       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
11416       *   see below). The inequality is determined according to
11417       *   {@link angular.equals} function. To save the value of the object for later comparison,
11418       *   the {@link angular.copy} function is used. It also means that watching complex options
11419       *   will have adverse memory and performance implications.
11420       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
11421       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
11422       *   iteration limit is 10 to prevent an infinite loop deadlock.
11423       *
11424       *
11425       * If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called,
11426       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
11427       * can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a
11428       * change is detected, be prepared for multiple calls to your listener.)
11429       *
11430       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
11431       * (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the
11432       * watcher. In rare cases, this is undesirable because the listener is called when the result
11433       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
11434       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
11435       * listener was called due to initialization.
11436       *
11437       * The example below contains an illustration of using a function as your $watch listener
11438       *
11439       *
11440       * # Example
11441       * <pre>
11442           // let's assume that scope was dependency injected as the $rootScope
11443           var scope = $rootScope;
11444           scope.name = 'misko';
11445           scope.counter = 0;
11446
11447           expect(scope.counter).toEqual(0);
11448           scope.$watch('name', function(newValue, oldValue) {
11449             scope.counter = scope.counter + 1;
11450           });
11451           expect(scope.counter).toEqual(0);
11452
11453           scope.$digest();
11454           // no variable change
11455           expect(scope.counter).toEqual(0);
11456
11457           scope.name = 'adam';
11458           scope.$digest();
11459           expect(scope.counter).toEqual(1);
11460
11461
11462
11463           // Using a listener function
11464           var food;
11465           scope.foodCounter = 0;
11466           expect(scope.foodCounter).toEqual(0);
11467           scope.$watch(
11468             // This is the listener function
11469             function() { return food; },
11470             // This is the change handler
11471             function(newValue, oldValue) {
11472               if ( newValue !== oldValue ) {
11473                 // Only increment the counter if the value changed
11474                 scope.foodCounter = scope.foodCounter + 1;
11475               }
11476             }
11477           );
11478           // No digest has been run so the counter will be zero
11479           expect(scope.foodCounter).toEqual(0);
11480
11481           // Run the digest but since food has not changed count will still be zero
11482           scope.$digest();
11483           expect(scope.foodCounter).toEqual(0);
11484
11485           // Update food and run digest.  Now the counter will increment
11486           food = 'cheeseburger';
11487           scope.$digest();
11488           expect(scope.foodCounter).toEqual(1);
11489
11490       * </pre>
11491       *
11492       *
11493       *
11494       * @param {(function()|string)} watchExpression Expression that is evaluated on each
11495       *    {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers
11496       *    a call to the `listener`.
11497       *
11498       *    - `string`: Evaluated as {@link guide/expression expression}
11499       *    - `function(scope)`: called with current `scope` as a parameter.
11500       * @param {(function()|string)=} listener Callback called whenever the return value of
11501       *   the `watchExpression` changes.
11502       *
11503       *    - `string`: Evaluated as {@link guide/expression expression}
11504       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
11505       *      parameters.
11506       *
11507       * @param {boolean=} objectEquality Compare object for equality rather than for reference.
11508       * @returns {function()} Returns a deregistration function for this listener.
11509       */
11510      $watch: function(watchExp, listener, objectEquality) {
11511        var scope = this,
11512            get = compileToFn(watchExp, 'watch'),
11513            array = scope.$$watchers,
11514            watcher = {
11515              fn: listener,
11516              last: initWatchVal,
11517              get: get,
11518              exp: watchExp,
11519              eq: !!objectEquality
11520            };
11521
11522        lastDirtyWatch = null;
11523
11524        // in the case user pass string, we need to compile it, do we really need this ?
11525        if (!isFunction(listener)) {
11526          var listenFn = compileToFn(listener || noop, 'listener');
11527          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
11528        }
11529
11530        if (typeof watchExp == 'string' && get.constant) {
11531          var originalFn = watcher.fn;
11532          watcher.fn = function(newVal, oldVal, scope) {
11533            originalFn.call(this, newVal, oldVal, scope);
11534            arrayRemove(array, watcher);
11535          };
11536        }
11537
11538        if (!array) {
11539          array = scope.$$watchers = [];
11540        }
11541        // we use unshift since we use a while loop in $digest for speed.
11542        // the while loop reads in reverse order.
11543        array.unshift(watcher);
11544
11545        return function() {
11546          arrayRemove(array, watcher);
11547          lastDirtyWatch = null;
11548        };
11549      },
11550
11551
11552      /**
11553       * @ngdoc function
11554       * @name ng.$rootScope.Scope#$watchCollection
11555       * @methodOf ng.$rootScope.Scope
11556       * @function
11557       *
11558       * @description
11559       * Shallow watches the properties of an object and fires whenever any of the properties change
11560       * (for arrays, this implies watching the array items; for object maps, this implies watching
11561       * the properties). If a change is detected, the `listener` callback is fired.
11562       *
11563       * - The `obj` collection is observed via standard $watch operation and is examined on every
11564       *   call to $digest() to see if any items have been added, removed, or moved.
11565       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
11566       *   adding, removing, and moving items belonging to an object or array.
11567       *
11568       *
11569       * # Example
11570       * <pre>
11571          $scope.names = ['igor', 'matias', 'misko', 'james'];
11572          $scope.dataCount = 4;
11573
11574          $scope.$watchCollection('names', function(newNames, oldNames) {
11575            $scope.dataCount = newNames.length;
11576          });
11577
11578          expect($scope.dataCount).toEqual(4);
11579          $scope.$digest();
11580
11581          //still at 4 ... no changes
11582          expect($scope.dataCount).toEqual(4);
11583
11584          $scope.names.pop();
11585          $scope.$digest();
11586
11587          //now there's been a change
11588          expect($scope.dataCount).toEqual(3);
11589       * </pre>
11590       *
11591       *
11592       * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
11593       *    expression value should evaluate to an object or an array which is observed on each
11594       *    {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the
11595       *    collection will trigger a call to the `listener`.
11596       *
11597       * @param {function(newCollection, oldCollection, scope)} listener a callback function that is
11598       *    fired with both the `newCollection` and `oldCollection` as parameters.
11599       *    The `newCollection` object is the newly modified data obtained from the `obj` expression
11600       *    and the `oldCollection` object is a copy of the former collection data.
11601       *    The `scope` refers to the current scope.
11602       *
11603       * @returns {function()} Returns a de-registration function for this listener. When the
11604       *    de-registration function is executed, the internal watch operation is terminated.
11605       */
11606      $watchCollection: function(obj, listener) {
11607        var self = this;
11608        var oldValue;
11609        var newValue;
11610        var changeDetected = 0;
11611        var objGetter = $parse(obj);
11612        var internalArray = [];
11613        var internalObject = {};
11614        var oldLength = 0;
11615
11616        function $watchCollectionWatch() {
11617          newValue = objGetter(self);
11618          var newLength, key;
11619
11620          if (!isObject(newValue)) {
11621            if (oldValue !== newValue) {
11622              oldValue = newValue;
11623              changeDetected++;
11624            }
11625          } else if (isArrayLike(newValue)) {
11626            if (oldValue !== internalArray) {
11627              // we are transitioning from something which was not an array into array.
11628              oldValue = internalArray;
11629              oldLength = oldValue.length = 0;
11630              changeDetected++;
11631            }
11632
11633            newLength = newValue.length;
11634
11635            if (oldLength !== newLength) {
11636              // if lengths do not match we need to trigger change notification
11637              changeDetected++;
11638              oldValue.length = oldLength = newLength;
11639            }
11640            // copy the items to oldValue and look for changes.
11641            for (var i = 0; i < newLength; i++) {
11642              if (oldValue[i] !== newValue[i]) {
11643                changeDetected++;
11644                oldValue[i] = newValue[i];
11645              }
11646            }
11647          } else {
11648            if (oldValue !== internalObject) {
11649              // we are transitioning from something which was not an object into object.
11650              oldValue = internalObject = {};
11651              oldLength = 0;
11652              changeDetected++;
11653            }
11654            // copy the items to oldValue and look for changes.
11655            newLength = 0;
11656            for (key in newValue) {
11657              if (newValue.hasOwnProperty(key)) {
11658                newLength++;
11659                if (oldValue.hasOwnProperty(key)) {
11660                  if (oldValue[key] !== newValue[key]) {
11661                    changeDetected++;
11662                    oldValue[key] = newValue[key];
11663                  }
11664                } else {
11665                  oldLength++;
11666                  oldValue[key] = newValue[key];
11667                  changeDetected++;
11668                }
11669              }
11670            }
11671            if (oldLength > newLength) {
11672              // we used to have more keys, need to find them and destroy them.
11673              changeDetected++;
11674              for(key in oldValue) {
11675                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
11676                  oldLength--;
11677                  delete oldValue[key];
11678                }
11679              }
11680            }
11681          }
11682          return changeDetected;
11683        }
11684
11685        function $watchCollectionAction() {
11686          listener(newValue, oldValue, self);
11687        }
11688
11689        return this.$watch($watchCollectionWatch, $watchCollectionAction);
11690      },
11691
11692      /**
11693       * @ngdoc function
11694       * @name ng.$rootScope.Scope#$digest
11695       * @methodOf ng.$rootScope.Scope
11696       * @function
11697       *
11698       * @description
11699       * Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and
11700       * its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change
11701       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers}
11702       * until no more listeners are firing. This means that it is possible to get into an infinite
11703       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
11704       * iterations exceeds 10.
11705       *
11706       * Usually, you don't call `$digest()` directly in
11707       * {@link ng.directive:ngController controllers} or in
11708       * {@link ng.$compileProvider#methods_directive directives}.
11709       * Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within
11710       * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
11711       *
11712       * If you want to be notified whenever `$digest()` is called,
11713       * you can register a `watchExpression` function with
11714       * {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`.
11715       *
11716       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
11717       *
11718       * # Example
11719       * <pre>
11720           var scope = ...;
11721           scope.name = 'misko';
11722           scope.counter = 0;
11723
11724           expect(scope.counter).toEqual(0);
11725           scope.$watch('name', function(newValue, oldValue) {
11726             scope.counter = scope.counter + 1;
11727           });
11728           expect(scope.counter).toEqual(0);
11729
11730           scope.$digest();
11731           // no variable change
11732           expect(scope.counter).toEqual(0);
11733
11734           scope.name = 'adam';
11735           scope.$digest();
11736           expect(scope.counter).toEqual(1);
11737       * </pre>
11738       *
11739       */
11740      $digest: function() {
11741        var watch, value, last,
11742            watchers,
11743            asyncQueue = this.$$asyncQueue,
11744            postDigestQueue = this.$$postDigestQueue,
11745            length,
11746            dirty, ttl = TTL,
11747            next, current, target = this,
11748            watchLog = [],
11749            logIdx, logMsg, asyncTask;
11750
11751        beginPhase('$digest');
11752
11753        lastDirtyWatch = null;
11754
11755        do { // "while dirty" loop
11756          dirty = false;
11757          current = target;
11758
11759          while(asyncQueue.length) {
11760            try {
11761              asyncTask = asyncQueue.shift();
11762              asyncTask.scope.$eval(asyncTask.expression);
11763            } catch (e) {
11764              clearPhase();
11765              $exceptionHandler(e);
11766            }
11767            lastDirtyWatch = null;
11768          }
11769
11770          traverseScopesLoop:
11771          do { // "traverse the scopes" loop
11772            if ((watchers = current.$$watchers)) {
11773              // process our watches
11774              length = watchers.length;
11775              while (length--) {
11776                try {
11777                  watch = watchers[length];
11778                  // Most common watches are on primitives, in which case we can short
11779                  // circuit it with === operator, only when === fails do we use .equals
11780                  if (watch) {
11781                    if ((value = watch.get(current)) !== (last = watch.last) &&
11782                        !(watch.eq
11783                            ? equals(value, last)
11784                            : (typeof value == 'number' && typeof last == 'number'
11785                               && isNaN(value) && isNaN(last)))) {
11786                      dirty = true;
11787                      lastDirtyWatch = watch;
11788                      watch.last = watch.eq ? copy(value) : value;
11789                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
11790                      if (ttl < 5) {
11791                        logIdx = 4 - ttl;
11792                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
11793                        logMsg = (isFunction(watch.exp))
11794                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
11795                            : watch.exp;
11796                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
11797                        watchLog[logIdx].push(logMsg);
11798                      }
11799                    } else if (watch === lastDirtyWatch) {
11800                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
11801                      // have already been tested.
11802                      dirty = false;
11803                      break traverseScopesLoop;
11804                    }
11805                  }
11806                } catch (e) {
11807                  clearPhase();
11808                  $exceptionHandler(e);
11809                }
11810              }
11811            }
11812
11813            // Insanity Warning: scope depth-first traversal
11814            // yes, this code is a bit crazy, but it works and we have tests to prove it!
11815            // this piece should be kept in sync with the traversal in $broadcast
11816            if (!(next = (current.$$childHead ||
11817                (current !== target && current.$$nextSibling)))) {
11818              while(current !== target && !(next = current.$$nextSibling)) {
11819                current = current.$parent;
11820              }
11821            }
11822          } while ((current = next));
11823
11824          // `break traverseScopesLoop;` takes us to here
11825
11826          if((dirty || asyncQueue.length) && !(ttl--)) {
11827            clearPhase();
11828            throw $rootScopeMinErr('infdig',
11829                '{0} $digest() iterations reached. Aborting!\n' +
11830                'Watchers fired in the last 5 iterations: {1}',
11831                TTL, toJson(watchLog));
11832          }
11833
11834        } while (dirty || asyncQueue.length);
11835
11836        clearPhase();
11837
11838        while(postDigestQueue.length) {
11839          try {
11840            postDigestQueue.shift()();
11841          } catch (e) {
11842            $exceptionHandler(e);
11843          }
11844        }
11845      },
11846
11847
11848      /**
11849       * @ngdoc event
11850       * @name ng.$rootScope.Scope#$destroy
11851       * @eventOf ng.$rootScope.Scope
11852       * @eventType broadcast on scope being destroyed
11853       *
11854       * @description
11855       * Broadcasted when a scope and its children are being destroyed.
11856       *
11857       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
11858       * clean up DOM bindings before an element is removed from the DOM.
11859       */
11860
11861      /**
11862       * @ngdoc function
11863       * @name ng.$rootScope.Scope#$destroy
11864       * @methodOf ng.$rootScope.Scope
11865       * @function
11866       *
11867       * @description
11868       * Removes the current scope (and all of its children) from the parent scope. Removal implies
11869       * that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer
11870       * propagate to the current scope and its children. Removal also implies that the current
11871       * scope is eligible for garbage collection.
11872       *
11873       * The `$destroy()` is usually used by directives such as
11874       * {@link ng.directive:ngRepeat ngRepeat} for managing the
11875       * unrolling of the loop.
11876       *
11877       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
11878       * Application code can register a `$destroy` event handler that will give it a chance to
11879       * perform any necessary cleanup.
11880       *
11881       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
11882       * clean up DOM bindings before an element is removed from the DOM.
11883       */
11884      $destroy: function() {
11885        // we can't destroy the root scope or a scope that has been already destroyed
11886        if (this.$$destroyed) return;
11887        var parent = this.$parent;
11888
11889        this.$broadcast('$destroy');
11890        this.$$destroyed = true;
11891        if (this === $rootScope) return;
11892
11893        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
11894
11895        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
11896        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
11897        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
11898        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
11899
11900        // This is bogus code that works around Chrome's GC leak
11901        // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
11902        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
11903            this.$$childTail = null;
11904      },
11905
11906      /**
11907       * @ngdoc function
11908       * @name ng.$rootScope.Scope#$eval
11909       * @methodOf ng.$rootScope.Scope
11910       * @function
11911       *
11912       * @description
11913       * Executes the `expression` on the current scope and returns the result. Any exceptions in
11914       * the expression are propagated (uncaught). This is useful when evaluating Angular
11915       * expressions.
11916       *
11917       * # Example
11918       * <pre>
11919           var scope = ng.$rootScope.Scope();
11920           scope.a = 1;
11921           scope.b = 2;
11922
11923           expect(scope.$eval('a+b')).toEqual(3);
11924           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
11925       * </pre>
11926       *
11927       * @param {(string|function())=} expression An angular expression to be executed.
11928       *
11929       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
11930       *    - `function(scope)`: execute the function with the current `scope` parameter.
11931       *
11932       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
11933       * @returns {*} The result of evaluating the expression.
11934       */
11935      $eval: function(expr, locals) {
11936        return $parse(expr)(this, locals);
11937      },
11938
11939      /**
11940       * @ngdoc function
11941       * @name ng.$rootScope.Scope#$evalAsync
11942       * @methodOf ng.$rootScope.Scope
11943       * @function
11944       *
11945       * @description
11946       * Executes the expression on the current scope at a later point in time.
11947       *
11948       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
11949       * that:
11950       *
11951       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
11952       *     rendering).
11953       *   - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after
11954       *     `expression` execution.
11955       *
11956       * Any exceptions from the execution of the expression are forwarded to the
11957       * {@link ng.$exceptionHandler $exceptionHandler} service.
11958       *
11959       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
11960       * will be scheduled. However, it is encouraged to always call code that changes the model
11961       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
11962       *
11963       * @param {(string|function())=} expression An angular expression to be executed.
11964       *
11965       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
11966       *    - `function(scope)`: execute the function with the current `scope` parameter.
11967       *
11968       */
11969      $evalAsync: function(expr) {
11970        // if we are outside of an $digest loop and this is the first time we are scheduling async
11971        // task also schedule async auto-flush
11972        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
11973          $browser.defer(function() {
11974            if ($rootScope.$$asyncQueue.length) {
11975              $rootScope.$digest();
11976            }
11977          });
11978        }
11979
11980        this.$$asyncQueue.push({scope: this, expression: expr});
11981      },
11982
11983      $$postDigest : function(fn) {
11984        this.$$postDigestQueue.push(fn);
11985      },
11986
11987      /**
11988       * @ngdoc function
11989       * @name ng.$rootScope.Scope#$apply
11990       * @methodOf ng.$rootScope.Scope
11991       * @function
11992       *
11993       * @description
11994       * `$apply()` is used to execute an expression in angular from outside of the angular
11995       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
11996       * Because we are calling into the angular framework we need to perform proper scope life
11997       * cycle of {@link ng.$exceptionHandler exception handling},
11998       * {@link ng.$rootScope.Scope#methods_$digest executing watches}.
11999       *
12000       * ## Life cycle
12001       *
12002       * # Pseudo-Code of `$apply()`
12003       * <pre>
12004           function $apply(expr) {
12005             try {
12006               return $eval(expr);
12007             } catch (e) {
12008               $exceptionHandler(e);
12009             } finally {
12010               $root.$digest();
12011             }
12012           }
12013       * </pre>
12014       *
12015       *
12016       * Scope's `$apply()` method transitions through the following stages:
12017       *
12018       * 1. The {@link guide/expression expression} is executed using the
12019       *    {@link ng.$rootScope.Scope#methods_$eval $eval()} method.
12020       * 2. Any exceptions from the execution of the expression are forwarded to the
12021       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12022       * 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the
12023       *    expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method.
12024       *
12025       *
12026       * @param {(string|function())=} exp An angular expression to be executed.
12027       *
12028       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12029       *    - `function(scope)`: execute the function with current `scope` parameter.
12030       *
12031       * @returns {*} The result of evaluating the expression.
12032       */
12033      $apply: function(expr) {
12034        try {
12035          beginPhase('$apply');
12036          return this.$eval(expr);
12037        } catch (e) {
12038          $exceptionHandler(e);
12039        } finally {
12040          clearPhase();
12041          try {
12042            $rootScope.$digest();
12043          } catch (e) {
12044            $exceptionHandler(e);
12045            throw e;
12046          }
12047        }
12048      },
12049
12050      /**
12051       * @ngdoc function
12052       * @name ng.$rootScope.Scope#$on
12053       * @methodOf ng.$rootScope.Scope
12054       * @function
12055       *
12056       * @description
12057       * Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for
12058       * discussion of event life cycle.
12059       *
12060       * The event listener function format is: `function(event, args...)`. The `event` object
12061       * passed into the listener has the following attributes:
12062       *
12063       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12064       *     `$broadcast`-ed.
12065       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12066       *   - `name` - `{string}`: name of the event.
12067       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12068       *     further event propagation (available only for events that were `$emit`-ed).
12069       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12070       *     to true.
12071       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12072       *
12073       * @param {string} name Event name to listen on.
12074       * @param {function(event, args...)} listener Function to call when the event is emitted.
12075       * @returns {function()} Returns a deregistration function for this listener.
12076       */
12077      $on: function(name, listener) {
12078        var namedListeners = this.$$listeners[name];
12079        if (!namedListeners) {
12080          this.$$listeners[name] = namedListeners = [];
12081        }
12082        namedListeners.push(listener);
12083
12084        var current = this;
12085        do {
12086          if (!current.$$listenerCount[name]) {
12087            current.$$listenerCount[name] = 0;
12088          }
12089          current.$$listenerCount[name]++;
12090        } while ((current = current.$parent));
12091
12092        var self = this;
12093        return function() {
12094          namedListeners[indexOf(namedListeners, listener)] = null;
12095          decrementListenerCount(self, 1, name);
12096        };
12097      },
12098
12099
12100      /**
12101       * @ngdoc function
12102       * @name ng.$rootScope.Scope#$emit
12103       * @methodOf ng.$rootScope.Scope
12104       * @function
12105       *
12106       * @description
12107       * Dispatches an event `name` upwards through the scope hierarchy notifying the
12108       * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
12109       *
12110       * The event life cycle starts at the scope on which `$emit` was called. All
12111       * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
12112       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12113       * registered listeners along the way. The event will stop propagating if one of the listeners
12114       * cancels it.
12115       *
12116       * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
12117       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12118       *
12119       * @param {string} name Event name to emit.
12120       * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
12121       * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
12122       */
12123      $emit: function(name, args) {
12124        var empty = [],
12125            namedListeners,
12126            scope = this,
12127            stopPropagation = false,
12128            event = {
12129              name: name,
12130              targetScope: scope,
12131              stopPropagation: function() {stopPropagation = true;},
12132              preventDefault: function() {
12133                event.defaultPrevented = true;
12134              },
12135              defaultPrevented: false
12136            },
12137            listenerArgs = concat([event], arguments, 1),
12138            i, length;
12139
12140        do {
12141          namedListeners = scope.$$listeners[name] || empty;
12142          event.currentScope = scope;
12143          for (i=0, length=namedListeners.length; i<length; i++) {
12144
12145            // if listeners were deregistered, defragment the array
12146            if (!namedListeners[i]) {
12147              namedListeners.splice(i, 1);
12148              i--;
12149              length--;
12150              continue;
12151            }
12152            try {
12153              //allow all listeners attached to the current scope to run
12154              namedListeners[i].apply(null, listenerArgs);
12155            } catch (e) {
12156              $exceptionHandler(e);
12157            }
12158          }
12159          //if any listener on the current scope stops propagation, prevent bubbling
12160          if (stopPropagation) return event;
12161          //traverse upwards
12162          scope = scope.$parent;
12163        } while (scope);
12164
12165        return event;
12166      },
12167
12168
12169      /**
12170       * @ngdoc function
12171       * @name ng.$rootScope.Scope#$broadcast
12172       * @methodOf ng.$rootScope.Scope
12173       * @function
12174       *
12175       * @description
12176       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12177       * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
12178       *
12179       * The event life cycle starts at the scope on which `$broadcast` was called. All
12180       * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
12181       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12182       * scope and calls all registered listeners along the way. The event cannot be canceled.
12183       *
12184       * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
12185       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12186       *
12187       * @param {string} name Event name to broadcast.
12188       * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
12189       * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
12190       */
12191      $broadcast: function(name, args) {
12192        var target = this,
12193            current = target,
12194            next = target,
12195            event = {
12196              name: name,
12197              targetScope: target,
12198              preventDefault: function() {
12199                event.defaultPrevented = true;
12200              },
12201              defaultPrevented: false
12202            },
12203            listenerArgs = concat([event], arguments, 1),
12204            listeners, i, length;
12205
12206        //down while you can, then up and next sibling or up and next sibling until back at root
12207        while ((current = next)) {
12208          event.currentScope = current;
12209          listeners = current.$$listeners[name] || [];
12210          for (i=0, length = listeners.length; i<length; i++) {
12211            // if listeners were deregistered, defragment the array
12212            if (!listeners[i]) {
12213              listeners.splice(i, 1);
12214              i--;
12215              length--;
12216              continue;
12217            }
12218
12219            try {
12220              listeners[i].apply(null, listenerArgs);
12221            } catch(e) {
12222              $exceptionHandler(e);
12223            }
12224          }
12225
12226          // Insanity Warning: scope depth-first traversal
12227          // yes, this code is a bit crazy, but it works and we have tests to prove it!
12228          // this piece should be kept in sync with the traversal in $digest
12229          // (though it differs due to having the extra check for $$listenerCount)
12230          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12231              (current !== target && current.$$nextSibling)))) {
12232            while(current !== target && !(next = current.$$nextSibling)) {
12233              current = current.$parent;
12234            }
12235          }
12236        }
12237
12238        return event;
12239      }
12240    };
12241
12242    var $rootScope = new Scope();
12243
12244    return $rootScope;
12245
12246
12247    function beginPhase(phase) {
12248      if ($rootScope.$$phase) {
12249        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12250      }
12251
12252      $rootScope.$$phase = phase;
12253    }
12254
12255    function clearPhase() {
12256      $rootScope.$$phase = null;
12257    }
12258
12259    function compileToFn(exp, name) {
12260      var fn = $parse(exp);
12261      assertArgFn(fn, name);
12262      return fn;
12263    }
12264
12265    function decrementListenerCount(current, count, name) {
12266      do {
12267        current.$$listenerCount[name] -= count;
12268
12269        if (current.$$listenerCount[name] === 0) {
12270          delete current.$$listenerCount[name];
12271        }
12272      } while ((current = current.$parent));
12273    }
12274
12275    /**
12276     * function used as an initial value for watchers.
12277     * because it's unique we can easily tell it apart from other values
12278     */
12279    function initWatchVal() {}
12280  }];
12281}
12282
12283/**
12284 * @description
12285 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
12286 */
12287function $$SanitizeUriProvider() {
12288  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12289    imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12290
12291  /**
12292   * @description
12293   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12294   * urls during a[href] sanitization.
12295   *
12296   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12297   *
12298   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12299   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12300   * regular expression. If a match is found, the original url is 
12300written into the dom. Otherwise,
12301   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12302   *
12303   * @param {RegExp=} regexp New regexp to whitelist urls with.
12304   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12305   *    chaining otherwise.
12306   */
12307  this.aHrefSanitizationWhitelist = function(regexp) {
12308    if (isDefined(regexp)) {
12309      aHrefSanitizationWhitelist = regexp;
12310      return this;
12311    }
12312    return aHrefSanitizationWhitelist;
12313  };
12314
12315
12316  /**
12317   * @description
12318   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12319   * urls during img[src] sanitization.
12320   *
12321   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12322   *
12323   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12324   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12325   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12326   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12327   *
12328   * @param {RegExp=} regexp New regexp to whitelist urls with.
12329   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12330   *    chaining otherwise.
12331   */
12332  this.imgSrcSanitizationWhitelist = function(regexp) {
12333    if (isDefined(regexp)) {
12334      imgSrcSanitizationWhitelist = regexp;
12335      return this;
12336    }
12337    return imgSrcSanitizationWhitelist;
12338  };
12339
12340  this.$get = function() {
12341    return function sanitizeUri(uri, isImage) {
12342      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12343      var normalizedVal;
12344      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12345      if (!msie || msie >= 8 ) {
12346        normalizedVal = urlResolve(uri).href;
12347        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
12348          return 'unsafe:'+normalizedVal;
12349        }
12350      }
12351      return uri;
12352    };
12353  };
12354}
12355
12356var $sceMinErr = minErr('$sce');
12357
12358var SCE_CONTEXTS = {
12359  HTML: 'html',
12360  CSS: 'css',
12361  URL: 'url',
12362  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
12363  // url.  (e.g. ng-include, script src, templateUrl)
12364  RESOURCE_URL: 'resourceUrl',
12365  JS: 'js'
12366};
12367
12368// Helper functions follow.
12369
12370// Copied from:
12371// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
12372// Prereq: s is a string.
12373function escapeForRegexp(s) {
12374  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
12375           replace(/\x08/g, '\\x08');
12376}
12377
12378
12379function adjustMatcher(matcher) {
12380  if (matcher === 'self') {
12381    return matcher;
12382  } else if (isString(matcher)) {
12383    // Strings match exactly except for 2 wildcards - '*' and '**'.
12384    // '*' matches any character except those from the set ':/.?&'.
12385    // '**' matches any character (like .* in a RegExp).
12386    // More than 2 *'s raises an error as it's ill defined.
12387    if (matcher.indexOf('***') > -1) {
12388      throw $sceMinErr('iwcard',
12389          'Illegal sequence *** in string matcher.  String: {0}', matcher);
12390    }
12391    matcher = escapeForRegexp(matcher).
12392                  replace('\\*\\*', '.*').
12393                  replace('\\*', '[^:/.?&;]*');
12394    return new RegExp('^' + matcher + '$');
12395  } else if (isRegExp(matcher)) {
12396    // The only other type of matcher allowed is a Regexp.
12397    // Match entire URL / disallow partial matches.
12398    // Flags are reset (i.e. no global, ignoreCase or multiline)
12399    return new RegExp('^' + matcher.source + '$');
12400  } else {
12401    throw $sceMinErr('imatcher',
12402        'Matchers may only be "self", string patterns or RegExp objects');
12403  }
12404}
12405
12406
12407function adjustMatchers(matchers) {
12408  var adjustedMatchers = [];
12409  if (isDefined(matchers)) {
12410    forEach(matchers, function(matcher) {
12411      adjustedMatchers.push(adjustMatcher(matcher));
12412    });
12413  }
12414  return adjustedMatchers;
12415}
12416
12417
12418/**
12419 * @ngdoc service
12420 * @name ng.$sceDelegate
12421 * @function
12422 *
12423 * @description
12424 *
12425 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
12426 * Contextual Escaping (SCE)} services to AngularJS.
12427 *
12428 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
12429 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
12430 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
12431 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
12432 * work because `$sce` delegates to `$sceDelegate` for these operations.
12433 *
12434 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
12435 *
12436 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
12437 * can override it completely to change the behavior of `$sce`, the common case would
12438 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
12439 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
12440 * templates.  Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist
12441 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
12442 * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12443 */
12444
12445/**
12446 * @ngdoc object
12447 * @name ng.$sceDelegateProvider
12448 * @description
12449 *
12450 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
12451 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
12452 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
12453 * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
12454 * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12455 *
12456 * For the general details about this service in Angular, read the main page for {@link ng.$sce
12457 * Strict Contextual Escaping (SCE)}.
12458 *
12459 * **Example**:  Consider the following case. <a name="example"></a>
12460 *
12461 * - your app is hosted at url `http://myapp.example.com/`
12462 * - but some of your templates are hosted on other domains you control such as
12463 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
12464 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
12465 *
12466 * Here is what a secure configuration for this scenario might look like:
12467 *
12468 * <pre class="prettyprint">
12469 *    angular.module('myApp', []).config(function($sceDelegateProvider) {
12470 *      $sceDelegateProvider.resourceUrlWhitelist([
12471 *        // Allow same origin resource loads.
12472 *        'self',
12473 *        // Allow loading from our assets domain.  Notice the difference between * and **.
12474 *        'http://srv*.assets.example.com/**']);
12475 *
12476 *      // The blacklist overrides the whitelist so the open redirect here is blocked.
12477 *      $sceDelegateProvider.resourceUrlBlacklist([
12478 *        'http://myapp.example.com/clickThru**']);
12479 *      });
12480 * </pre>
12481 */
12482
12483function $SceDelegateProvider() {
12484  this.SCE_CONTEXTS = SCE_CONTEXTS;
12485
12486  // Resource URLs can also be trusted by policy.
12487  var resourceUrlWhitelist = ['self'],
12488      resourceUrlBlacklist = [];
12489
12490  /**
12491   * @ngdoc function
12492   * @name ng.sceDelegateProvider#resourceUrlWhitelist
12493   * @methodOf ng.$sceDelegateProvider
12494   * @function
12495   *
12496   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
12497   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12498   *     changes to the array are ignored.
12499   *
12500   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
12501   *     allowed in this array.
vendor: 4,224 bytes, lines 12502-12628
12502   *
12503   *     Note: **an empty whitelist array will block all URLs**!
12504   *
12505   * @return {Array} the currently set whitelist array.
12506   *
12507   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
12508   * same origin resource requests.
12509   *
12510   * @description
12511   * Sets/Gets the whitelist of trusted resource URLs.
12512   */
12513  this.resourceUrlWhitelist = function (value) {
12514    if (arguments.length) {
12515      resourceUrlWhitelist = adjustMatchers(value);
12516    }
12517    return resourceUrlWhitelist;
12518  };
12519
12520  /**
12521   * @ngdoc function
12522   * @name ng.sceDelegateProvider#resourceUrlBlacklist
12523   * @methodOf ng.$sceDelegateProvider
12524   * @function
12525   *
12526   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
12527   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12528   *     changes to the array are ignored.
12529   *
12530   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
12531   *     allowed in this array.
12532   *
12533   *     The typical usage for the blacklist is to **block
12534   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
12535   *     these would otherwise be trusted but actually return content from the redirected domain.
12536   *
12537   *     Finally, **the blacklist overrides the whitelist** and has the final say.
12538   *
12539   * @return {Array} the currently set blacklist array.
12540   *
12541   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
12542   * is no blacklist.)
12543   *
12544   * @description
12545   * Sets/Gets the blacklist of trusted resource URLs.
12546   */
12547
12548  this.resourceUrlBlacklist = function (value) {
12549    if (arguments.length) {
12550      resourceUrlBlacklist = adjustMatchers(value);
12551    }
12552    return resourceUrlBlacklist;
12553  };
12554
12555  this.$get = ['$injector', function($injector) {
12556
12557    var htmlSanitizer = function htmlSanitizer(html) {
12558      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
12559    };
12560
12561    if ($injector.has('$sanitize')) {
12562      htmlSanitizer = $injector.get('$sanitize');
12563    }
12564
12565
12566    function matchUrl(matcher, parsedUrl) {
12567      if (matcher === 'self') {
12568        return urlIsSameOrigin(parsedUrl);
12569      } else {
12570        // definitely a regex.  See adjustMatchers()
12571        return !!matcher.exec(parsedUrl.href);
12572      }
12573    }
12574
12575    function isResourceUrlAllowedByPolicy(url) {
12576      var parsedUrl = urlResolve(url.toString());
12577      var i, n, allowed = false;
12578      // Ensure that at least one item from the whitelist allows this url.
12579      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
12580        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
12581          allowed = true;
12582          break;
12583        }
12584      }
12585      if (allowed) {
12586        // Ensure that no item from the blacklist blocked this url.
12587        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
12588          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
12589            allowed = false;
12590            break;
12591          }
12592        }
12593      }
12594      return allowed;
12595    }
12596
12597    function generateHolderType(Base) {
12598      var holderType = function TrustedValueHolderType(trustedValue) {
12599        this.$$unwrapTrustedValue = function() {
12600          return trustedValue;
12601        };
12602      };
12603      if (Base) {
12604        holderType.prototype = new Base();
12605      }
12606      holderType.prototype.valueOf = function sceValueOf() {
12607        return this.$$unwrapTrustedValue();
12608      };
12609      holderType.prototype.toString = function sceToString() {
12610        return this.$$unwrapTrustedValue().toString();
12611      };
12612      return holderType;
12613    }
12614
12615    var trustedValueHolderBase = generateHolderType(),
12616        byType = {};
12617
12618    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
12619    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
12620    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
12621    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
12622    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
12623
12624    /**
12625     * @ngdoc method
12626     * @name ng.$sceDelegate#trustAs
12627     * @methodOf ng.$sceDelegate
12628     *
12629     * @description
12630     * Returns an object that is trusted by angular for use in specified strict
12631     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
12632     * attribute interpolation, any dom event binding attribute interpolation
12633     * such as for onclick,  etc.) that uses the provided value.
12634     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
12635     *
12636     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
12637     *   resourceUrl, html, js and css.
12638     * @param {*} value The value that that should be considered trusted/safe.
12639     * @returns {*} A value that can be used to stand in for the provided `value` in places
12640     * where Angular expects a $sce.trustAs() return value.
12641     */
12642    function trustAs(type, trustedValue) {
12643      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
12644      if (!Constructor) {
12645        throw $sceMinErr('icontext',
12646            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
12647            type, trustedValue);
12648      }
12649      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
12650        return trustedValue;
12651      }
12652      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
12653      // mutable objects, we ensure here that the value passed in is actually a string.
12654      if (typeof trustedValue !== 'string') {
12655        throw $sceMinErr('itype',
12656            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
12657            type);
12658      }
12659      return new Constructor(trustedValue);
12660    }
12661
12662    /**
12663     * @ngdoc method
12664     * @name ng.$sceDelegate#valueOf
12665     * @methodOf ng.$sceDelegate
12666     *
12667     * @description
12668     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs
12669     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
12670     * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.
12671     *
12672     * If the passed parameter is not a value that had been returned by {@link
12673     * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is.
12674     *
12675     * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
12676     *      call or anything else.
12677     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#methods_trustAs
12678     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
12679     *     `value` unchanged.
12680     */
12681    function valueOf(maybeTrusted) {
12682      if (maybeTrusted instanceof trustedValueHolderBase) {
12683        return maybeTrusted.$$unwrapTrustedValue();
12684      } else {
12685        return maybeTrusted;
12686      }
12687    }
12688
12689    /**
12690     * @ngdoc method
12691     * @name ng.$sceDelegate#getTrusted
12692     * @methodOf ng.$sceDelegate
12693     *
12694     * @description
12695     * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and
12696     * returns the originally supplied value if the queried context type is a supertype of the
12697     * created type.  If this condition isn't satisfied, throws an exception.
12698     *
12699     * @param {string} type The kind of context in which this value is to be used.
12700     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs
12701     *     `$sceDelegate.trustAs`} call.
12702     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
12703     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
12704     */
12705    function getTrusted(type, maybeTrusted) {
12706      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
12707        return maybeTrusted;
12708      }
12709      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
12710      if (constructor && maybeTrusted instanceof constructor) {
12711        return maybeTrusted.$$unwrapTrustedValue();
12712      }
12713      // If we get here, then we may only take one of two actions.
12714      // 1. sanitize the value for the requested type, or
12715      // 2. throw an exception.
12716      if (type === SCE_CONTEXTS.RESOURCE_URL) {
12717        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
12718          return maybeTrusted;
12719        } else {
12720          throw $sceMinErr('insecurl',
12721              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
12722              maybeTrusted.toString());
12723        }
12724      } else if (type === SCE_CONTEXTS.HTML) {
12725        return htmlSanitizer(maybeTrusted);
12726      }
12727      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
12728    }
12729
12730    return { trustAs: trustAs,
12731             getTrusted: getTrusted,
12732             valueOf: valueOf };
12733  }];
12734}
12735
12736
12737/**
12738 * @ngdoc object
12739 * @name ng.$sceProvider
12740 * @description
12741 *
12742 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
12743 * -   enable/disable Strict Contextual Escaping (SCE) in a module
12744 * -   override the default implementation with a custom delegate
12745 *
12746 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
12747 */
12748
12749/* jshint maxlen: false*/
12750
12751/**
12752 * @ngdoc service
12753 * @name ng.$sce
12754 * @function
12755 *
12756 * @description
12757 *
12758 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
12759 *
12760 * # Strict Contextual Escaping
12761 *
12762 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
12763 * contexts to result in a value that is marked as safe to use for that context.  One example of
12764 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
12765 * to these contexts as privileged or SCE contexts.
12766 *
12767 * As of version 1.2, Angular ships with SCE enabled by default.
12768 *
12769 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
12770 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
12771 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
12772 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
12773 * to the top of your HTML document.
12774 *
12775 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
12776 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
12777 *
12778 * Here's an example of a binding in a privileged context:
12779 *
12780 * <pre class="prettyprint">
12781 *     <input ng-model="userHtml">
12782 *     <div ng-bind-html="userHtml">
12783 * </pre>
12784 *
12785 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
12786 * disabled, this application allows the user to render arbitrary HTML into the DIV.
12787 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
12788 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
12789 * security vulnerabilities.)
12790 *
12791 * For the case of HTML, you might use a library, either on the client side, or on the server side,
12792 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
12793 *
12794 * How would you ensure that every place that used these types of bindings was bound to a value that
12795 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
12796 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
12797 * properties/fields and forgot to update the binding to the sanitized value?
12798 *
12799 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
12800 * determine that something explicitly says it's safe to use a value for binding in that
12801 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
12802 * for those values that you can easily tell are safe - because they were received from your server,
12803 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
12804 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
12805 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
12806 *
12807 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs} 
12808 * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to
12809 * obtain values that will be accepted by SCE / privileged contexts.
12810 *
12811 *
12812 * ## How does it work?
12813 *
12814 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted
12815 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
12816 * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
12817 * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
12818 *
12819 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
12820 * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
12821 * simplified):
12822 *
12823 * <pre class="prettyprint">
12824 *   var ngBindHtmlDirective = ['$sce', function($sce) {
12825 *     return function(scope, element, attr) {
12826 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
12827 *         element.html(value || '');
12828 *       });
12829 *     };
12830 *   }];
12831 * </pre>
12832 *
12833 * ## Impact on loading templates
12834 *
12835 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
12836 * `templateUrl`'s specified by {@link guide/directive directives}.
12837 *
12838 * By default, Angular only loads templates from the same domain and protocol as the application
12839 * document.  This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
12840 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
12841 * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist
12842 * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value.
12843 *
12844 * *Please note*:
12845 * The browser's
12846 * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
12847 * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
12848 * policy apply in addition to this and may further restrict whether the template is successfully
12849 * loaded.  This means that without the right CORS policy, loading templates from a different domain
12850 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
12851 * browsers.
12852 *
12853 * ## This feels like too much overhead for the developer?
12854 *
12855 * It's important to remember that SCE only applies to interpolation expressions.
12856 *
12857 * If your expressions are constant literals, they're automatically trusted and you don't need to
12858 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
12859 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
12860 *
12861 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
12862 * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
12863 *
12864 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
12865 * templates in `ng-include` from your application's domain without having to even know about SCE.
12866 * It blocks loading templates from other domains or loading templates over http from an https
12867 * served document.  You can change these by setting your own custom {@link
12868 * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link
12869 * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs.
12870 *
12871 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
12872 * application that's secure and can be audited to verify that with much more ease than bolting
12873 * security onto an application later.
12874 *
12875 * <a name="contexts"></a>
12876 * ## What trusted context types are supported?
12877 *
12878 * | Context             | Notes          |
12879 * |---------------------|----------------|
12880 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
12881 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
12882 * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
12883 * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens 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. |
12884 * | `$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. |
12885 *
12886 * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
12887 *
12888 *  Each element in these arrays must be one of the following:
12889 *
12890 *  - **'self'**
12891 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
12892 *      domain** as the application document using the **same protocol**.
12893 *  - **String** (except the special value `'self'`)
12894 *    - The string is matched against the full *normalized / absolute URL* of the resource
12895 *      being tested (substring matches are not good enough.)
12896 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
12897 *      match themselves.
12898 *    - `*`: matches zero or more occurances of any character other than one of the following 6
12899 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
12900 *      in a whitelist.
12901 *    - `**`: matches zero or more occurances of *any* character.  As such, it's not
12902 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
12903 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
12904 *      not have been the intention.)  It's usage at the very end of the path is ok.  (e.g.
12905 *      http://foo.example.com/templates/**).
12906 *  - **RegExp** (*see caveat below*)
12907 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
12908 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
12909 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
12910 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
12911 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
12912 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
12913 *      is highly recommended to use the string patterns and only fall back to regular expressions
12914 *      if they as a last resort.
12915 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
12916 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
12917 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
12918 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
12919 *    - If you are generating your JavaScript from some other templating engine (not
12920 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
12921 *      remember to escape your regular expression (and be aware that you might need more than
12922 *      one level of escaping depending on your templating engine and the way you interpolated
12923 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
12924 *      enough before coding your own.  e.g. Ruby has
12925 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
12926 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
12927 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
12928 *      Closure library's [goog.string.regExpEscape(s)](
12929 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
12930 *
12931 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
12932 *
12933 * ## Show me an example using SCE.
12934 *
12935 * @example
12936<example module="mySceApp" deps="angular-sanitize.js">
12937<file name="index.html">
12938  <div ng-controller="myAppController as myCtrl">
12939    <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
12940    <b>User comments</b><br>
12941    By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
12942    $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
12943    exploit.
12944    <div class="well">
12945      <div ng-repeat="userComment in myCtrl.userComments">
12946        <b>{{userComment.name}}</b>:
12947        <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
12948        <br>
12949      </div>
12950    </div>
12951  </div>
12952</file>
12953
12954<file name="script.js">
12955  var mySceApp = angular.module('mySceApp', ['ngSanitize']);
12956
12957  mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
12958    var self = this;
12959    $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
12960      self.userComments = userComments;
12961    });
12962    self.explicitlyTrustedHtml = $sce.trustAsHtml(
12963        '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
12964        'sanitization.&quot;">Hover over this text.</span>');
12965  });
12966</file>
12967
12968<file name="test_data.json">
12969[
12970  { "name": "Alice",
12971    "htmlComment":
12972        "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
12973  },
12974  { "name": "Bob",
12975    "htmlComment": "<i>Yes!</i>  Am I the only other one?"
12976  }
12977]
12978</file>
12979
12980<file name="scenario.js">
12981  describe('SCE doc demo', function() {
12982    it('should sanitize untrusted values', function() {
12983      expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
12984    });
12985    it('should NOT sanitize explicitly trusted values', function() {
12986      expect(element('#explicitlyTrustedHtml').html()).toBe(
12987          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
12988          'sanitization.&quot;">Hover over this text.</span>');
12989    });
12990  });
12991</file>
12992</example>
12993 *
12994 *
12995 *
12996 * ## Can I disable SCE completely?
12997 *
12998 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
12999 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13000 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13001 * for cases where you have a lot of existing code that was written before SCE was introduced and
13002 * you're migrating them a module at a time.
13003 *
13004 * That said, here's how you can completely disable SCE:
13005 *
13006 * <pre class="prettyprint">
13007 *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13008 *     // Completely disable SCE.  For demonstration purposes only!
13009 *     // Do not use in new projects.
13010 *     $sceProvider.enabled(false);
13011 *   });
13012 * </pre>
13013 *
13014 */
13015/* jshint maxlen: 100 */
13016
13017function $SceProvider() {
13018  var enabled = true;
13019
13020  /**
13021   * @ngdoc function
13022   * @name ng.sceProvider#enabled
13023   * @methodOf ng.$sceProvider
13024   * @function
13025   *
13026   * @param {boolean=} value If provided, then enables/disables SCE.
13027   * @return {boolean} true if SCE is enabled, false otherwise.
13028   *
13029   * @description
13030   * Enables/disables SCE and returns the current value.
13031   */
13032  this.enabled = function (value) {
13033    if (arguments.length) {
13034      enabled = !!value;
13035    }
13036    return enabled;
13037  };
13038
13039
13040  /* Design notes on the default implementation for SCE.
13041   *
13042   * The API contract for the SCE delegate
13043   * -------------------------------------
13044   * The SCE delegate object must provide the following 3 methods:
13045   *
13046   * - trustAs(contextEnum, value)
13047   *     This method is used to tell the SCE service that the provided value is OK to use in the
13048   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13049   *     getTrusted() for a compatible contextEnum and return this value.
13050   *
13051   * - valueOf(value)
13052   *     For values that were not produced by trustAs(), return them as is.  For values that were
13053   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13054   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13055   *     such a value.
13056   *
13057   * - getTrusted(contextEnum, value)
13058   *     This function should return the a value that is safe to use in the context specified by
13059   *     contextEnum or throw and exception otherwise.
13060   *
13061   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13062   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13063   * instance, an implementation could maintain a registry of all trusted objects by context.  In
13064   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13065   * return the same object passed in if it was found in the registry under a compatible context or
13066   * throw an exception otherwise.  An implementation might only wrap values some of the time based
13067   * on some criteria.  getTrusted() might return a value and not throw an exception for special
13068   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13069   *
13070   *
13071   * A note on the inheritance model for SCE contexts
13072   * ------------------------------------------------
13073   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13074   * is purely an implementation details.
13075   *
13076   * The contract is simply this:
13077   *
13078   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13079   *     will also succeed.
13080   *
13081   * Inheritance happens to capture this in a natural way.  In some future, we
13082   * may not use inheritance anymore.  That is OK because no code outside of
13083   * sce.js and sceSpecs.js would need to be aware of this detail.
13084   */
13085
13086  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13087                $parse,   $sniffer,   $sceDelegate) {
13088    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13089    // the "expression(javascript expression)" syntax which is insecure.
13090    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13091      throw $sceMinErr('iequirks',
13092        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13093        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13094        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13095    }
13096
13097    var sce = copy(SCE_CONTEXTS);
13098
13099    /**
13100     * @ngdoc function
13101     * @name ng.sce#isEnabled
13102     * @methodOf ng.$sce
13103     * @function
13104     *
13105     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13106     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13107     *
13108     * @description
13109     * Returns a boolean indicating if SCE is enabled.
13110     */
13111    sce.isEnabled = function () {
13112      return enabled;
13113    };
13114    sce.trustAs = $sceDelegate.trustAs;
13115    sce.getTrusted = $sceDelegate.getTrusted;
13116    sce.valueOf = $sceDelegate.valueOf;
13117
13118    if (!enabled) {
13119      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13120      sce.valueOf = identity;
13121    }
13122
13123    /**
13124     * @ngdoc method
13125     * @name ng.$sce#parse
13126     * @methodOf ng.$sce
13127     *
13128     * @description
13129     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13130     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13131     * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*,
13132     * *result*)}
13133     *
13134     * @param {string} type The kind of SCE context in which this result will be used.
13135     * @param {string} expression String expression to compile.
13136     * @returns {function(context, locals)} a function which represents the compiled expression:
13137     *
13138     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13139     *      are evaluated against (typically a scope object).
13140     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13141     *      `context`.
13142     */
13143    sce.parseAs = function sceParseAs(type, expr) {
13144      var parsed = $parse(expr);
13145      if (parsed.literal && parsed.constant) {
13146        return parsed;
13147      } else {
13148        return function sceParseAsTrusted(self, locals) {
13149          return sce.getTrusted(type, parsed(self, locals));
13150        };
13151      }
13152    };
13153
13154    /**
13155     * @ngdoc method
13156     * @name ng.$sce#trustAs
13157     * @methodOf ng.$sce
13158     *
13159     * @description
13160     * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.  As such,
13161     * returns an object that is trusted by angular for use in specified strict contextual
13162     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13163     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13164     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13165     * escaping.
13166     *
13167     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13168     *   resource_url, html, js and css.
13169     * @param {*} value The value that that should be considered trusted/safe.
13170     * @returns {*} A value that can be used to stand in for the provided `value` in places
13171     * where Angular expects a $sce.trustAs() return value.
13172     */
13173
13174    /**
13175     * @ngdoc method
13176     * @name ng.$sce#trustAsHtml
13177     * @methodOf ng.$sce
13178     *
13179     * @description
13180     * Shorthand method.  `$sce.trustAsHtml(value)` →
13181     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13182     *
13183     * @param {*} value The value to trustAs.
13184     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml
13185     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13186     *     only accept expressions that are either literal constants or are the
13187     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13188     */
13189
13190    /**
13191     * @ngdoc method
13192     * @name ng.$sce#trustAsUrl
13193     * @methodOf ng.$sce
13194     *
13195     * @description
13196     * Shorthand method.  `$sce.trustAsUrl(value)` →
13197     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13198     *
13199     * @param {*} value The value to trustAs.
13200     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl
13201     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13202     *     only accept expressions that are either literal constants or are the
13203     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13204     */
13205
13206    /**
13207     * @ngdoc method
13208     * @name ng.$sce#trustAsResourceUrl
13209     * @methodOf ng.$sce
13210     *
13211     * @description
13212     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13213     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13214     *
13215     * @param {*} value The value to trustAs.
13216     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl
13217     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13218     *     only accept expressions that are either literal constants or are the return
13219     *     value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13220     */
13221
13222    /**
13223     * @ngdoc method
13224     * @name ng.$sce#trustAsJs
13225     * @methodOf ng.$sce
13226     *
13227     * @description
13228     * Shorthand method.  `$sce.trustAsJs(value)` →
13229     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13230     *
13231     * @param {*} value The value to trustAs.
13232     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs
13233     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13234     *     only accept expressions that are either literal constants or are the
13235     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13236     */
13237
13238    /**
13239     * @ngdoc method
13240     * @name ng.$sce#getTrusted
13241     * @methodOf ng.$sce
13242     *
13243     * @description
13244     * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}.  As such,
13245     * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the
13246     * originally supplied value if the queried context type is a supertype of the created type.
13247     * If this condition isn't satisfied, throws an exception.
13248     *
13249     * @param {string} type The kind of context in which this value is to be used.
13250     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`}
13251     *                         call.
13252     * @returns {*} The value the was originally provided to
13253     *              {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context.
13254     *              Otherwise, throws an exception.
13255     */
13256
13257    /**
13258     * @ngdoc method
13259     * @name ng.$sce#getTrustedHtml
13260     * @methodOf ng.$sce
13261     *
13262     * @description
13263     * Shorthand method.  `$sce.getTrustedHtml(value)` →
13264     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13265     *
13266     * @param {*} value The value to pass to `$sce.getTrusted`.
13267     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13268     */
13269
13270    /**
13271     * @ngdoc method
13272     * @name ng.$sce#getTrustedCss
13273     * @methodOf ng.$sce
13274     *
13275     * @description
13276     * Shorthand method.  `$sce.getTrustedCss(value)` →
13277     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13278     *
13279     * @param {*} value The value to pass to `$sce.getTrusted`.
13280     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13281     */
13282
13283    /**
13284     * @ngdoc method
13285     * @name ng.$sce#getTrustedUrl
13286     * @methodOf ng.$sce
13287     *
13288     * @description
13289     * Shorthand method.  `$sce.getTrustedUrl(value)` →
13290     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13291     *
13292     * @param {*} value The value to pass to `$sce.getTrusted`.
13293     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13294     */
13295
13296    /**
13297     * @ngdoc method
13298     * @name ng.$sce#getTrustedResourceUrl
13299     * @methodOf ng.$sce
13300     *
13301     * @description
13302     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
13303     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
13304     *
13305     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
13306     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
13307     */
13308
13309    /**
13310     * @ngdoc method
13311     * @name ng.$sce#getTrustedJs
13312     * @methodOf ng.$sce
13313     *
13314     * @description
13315     * Shorthand method.  `$sce.getTrustedJs(value)` →
13316     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
13317     *
13318     * @param {*} value The value to pass to `$sce.getTrusted`.
13319     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
13320     */
13321
13322    /**
13323     * @ngdoc method
13324     * @name ng.$sce#parseAsHtml
13325     * @methodOf ng.$sce
13326     *
13327     * @description
13328     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
13329     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`}
13330     *
13331     * @param {string} expression String expression to compile.
13332     * @returns {function(context, locals)} a function which represents the compiled expression:
13333     *
13334     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13335     *      are evaluated against (typically a scope object).
13336     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13337     *      `context`.
13338     */
13339
13340    /**
13341     * @ngdoc method
13342     * @name ng.$sce#parseAsCss
13343     * @methodOf ng.$sce
13344     *
13345     * @description
13346     * Shorthand method.  `$sce.parseAsCss(value)` →
13347     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`}
13348     *
13349     * @param {string} expression String expression to compile.
13350     * @returns {function(context, locals)} a function which represents the compiled expression:
13351     *
13352     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13353     *      are evaluated against (typically a scope object).
13354     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13355     *      `context`.
13356     */
13357
13358    /**
13359     * @ngdoc method
13360     * @name ng.$sce#parseAsUrl
13361     * @methodOf ng.$sce
13362     *
13363     * @description
13364     * Shorthand method.  `$sce.parseAsUrl(value)` →
13365     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`}
13366     *
13367     * @param {string} expression String expression to compile.
13368     * @returns {function(context, locals)} a function which represents the compiled expression:
13369     *
13370     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13371     *      are evaluated against (typically a scope object).
13372     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13373     *      `context`.
13374     */
13375
13376    /**
13377     * @ngdoc method
13378     * @name ng.$sce#parseAsResourceUrl
13379     * @methodOf ng.$sce
13380     *
13381     * @description
13382     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
13383     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
13384     *
13385     * @param {string} expression String expression to compile.
13386     * @returns {function(context, locals)} a function which represents the compiled expression:
13387     *
13388     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13389     *      are evaluated against (typically a scope object).
13390     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13391     *      `context`.
13392     */
13393
13394    /**
13395     * @ngdoc method
13396     * @name ng.$sce#parseAsJs
13397     * @methodOf ng.$sce
13398     *
13399     * @description
13400     * Shorthand method.  `$sce.parseAsJs(value)` →
13401     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`}
13402     *
13403     * @param {string} expression String expression to compile.
13404     * @returns {function(context, locals)} a function which represents the compiled expression:
13405     *
13406     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13407     *      are evaluated against (typically a scope object).
13408     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13409     *      `context`.
13410     */
13411
13412    // Shorthand delegations.
13413    var parse = sce.parseAs,
13414        getTrusted = sce.getTrusted,
13415        trustAs = sce.trustAs;
13416
13417    forEach(SCE_CONTEXTS, function (enumValue, name) {
13418      var lName = lowercase(name);
13419      sce[camelCase("parse_as_" + lName)] = function (expr) {
13420        return parse(enumValue, expr);
13421      };
13422      sce[camelCase("get_trusted_" + lName)] = function (value) {
13423        return getTrusted(enumValue, value);
13424      };
13425      sce[camelCase("trust_as_" + lName)] = function (value) {
13426        return trustAs(enumValue, value);
13427      };
13428    });
13429
13430    return sce;
13431  }];
13432}
13433
13434/**
13435 * !!! This is an undocumented "private" service !!!
13436 *
13437 * @name ng.$sniffer
13438 * @requires $window
13439 * @requires $document
13440 *
13441 * @property {boolean} history Does the browser support html5 history api ?
13442 * @property {boolean} hashchange Does the browser support hashchange event ?
13443 * @property {boolean} transitions Does the browser support CSS transition events ?
13444 * @property {boolean} animations Does the browser support CSS animation events ?
13445 *
13446 * @description
13447 * This is very simple implementation of testing browser's features.
13448 */
13449function $SnifferProvider() {
13450  this.$get = ['$window', '$document', function($window, $document) {
13451    var eventSupport = {},
13452        android =
13453          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
13454        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
13455        document = $document[0] || {},
13456        documentMode = document.documentMode,
13457        vendorPrefix,
13458        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
13459        bodyStyle = document.body && document.body.style,
13460        transitions = false,
13461        animations = false,
13462        match;
13463
13464    if (bodyStyle) {
13465      for(var prop in bodyStyle) {
13466        if(match = vendorRegex.exec(prop)) {
13467          vendorPrefix = match[0];
13468          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
13469          break;
13470        }
13471      }
13472
13473      if(!vendorPrefix) {
13474        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
13475      }
13476
13477      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
13478      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
13479
13480      if (android && (!transitions||!animations)) {
13481        transitions = isString(document.body.style.webkitTransition);
13482        animations = isString(document.body.style.webkitAnimation);
13483      }
13484    }
13485
13486
13487    return {
13488      // Android has history.pushState, but it does not update location correctly
13489      // so let's not use the history API at all.
13490      // http://code.google.com/p/android/issues/detail?id=17471
13491      // https://github.com/angular/angular.js/issues/904
13492
13493      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
13494      // so let's not use the history API also
13495      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
13496      // jshint -W018
13497      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
13498      // jshint +W018
13499      hashchange: 'onhashchange' in $window &&
13500                  // IE8 compatible mode lies
13501                  (!documentMode || documentMode > 7),
13502      hasEvent: function(event) {
13503        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
13504        // it. In particular the event is not fired when backspace or delete key are pressed or
13505        // when cut operation is performed.
13506        if (event == 'input' && msie == 9) return false;
13507
13508        if (isUndefined(eventSupport[event])) {
13509          var divElm = document.createElement('div');
13510          eventSupport[event] = 'on' + event in divElm;
13511        }
13512
13513        return eventSupport[event];
13514      },
13515      csp: csp(),
13516      vendorPrefix: vendorPrefix,
13517      transitions : transitions,
13518      animations : animations,
13519      android: android,
13520      msie : msie,
13521      msieDocumentMode: documentMode
13522    };
13523  }];
13524}
13525
13526function $TimeoutProvider() {
13527  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
13528       function($rootScope,   $browser,   $q,   $exceptionHandler) {
13529    var deferreds = {};
13530
13531
13532     /**
13533      * @ngdoc function
13534      * @name ng.$timeout
13535      * @requires $browser
13536      *
13537      * @description
13538      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
13539      * block and delegates any exceptions to
13540      * {@link ng.$exceptionHandler $exceptionHandler} service.
13541      *
13542      * The return value of registering a timeout function is a promise, which will be resolved when
13543      * the timeout is reached and the timeout function is executed.
13544      *
13545      * To cancel a timeout request, call `$timeout.cancel(promise)`.
13546      *
13547      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
13548      * synchronously flush the queue of deferred functions.
13549      *
13550      * @param {function()} fn A function, whose execution should be delayed.
13551      * @param {number=} [delay=0] Delay in milliseconds.
13552      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
13553      *   will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
13554      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
13555      *   promise will be resolved with is the return value of the `fn` function.
13556      * 
13557      */
13558    function timeout(fn, delay, invokeApply) {
13559      var deferred = $q.defer(),
13560          promise = deferred.promise,
13561          skipApply = (isDefined(invokeApply) && !invokeApply),
13562          timeoutId;
13563
13564      timeoutId = $browser.defer(function() {
13565        try {
13566          deferred.resolve(fn());
13567        } catch(e) {
13568          deferred.reject(e);
13569          $exceptionHandler(e);
13570        }
13571        finally {
13572          delete deferreds[promise.$$timeoutId];
13573        }
13574
13575        if (!skipApply) $rootScope.$apply();
13576      }, delay);
13577
13578      promise.$$timeoutId = timeoutId;
13579      deferreds[timeoutId] = deferred;
13580
13581      return promise;
13582    }
13583
13584
13585     /**
13586      * @ngdoc function
13587      * @name ng.$timeout#cancel
13588      * @methodOf ng.$timeout
13589      *
13590      * @description
13591      * Cancels a task associated with the `promise`. As a result of this, the promise will be
13592      * resolved with a rejection.
13593      *
13594      * @param {Promise=} promise Promise returned by the `$timeout` function.
13595      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
13596      *   canceled.
13597      */
13598    timeout.cancel = function(promise) {
13599      if (promise && promise.$$timeoutId in deferreds) {
13600        deferreds[promise.$$timeoutId].reject('canceled');
13601        delete deferreds[promise.$$timeoutId];
13602        return $browser.defer.cancel(promise.$$timeoutId);
13603      }
13604      return false;
13605    };
13606
13607    return timeout;
13608  }];
13609}
13610
13611// NOTE:  The usage of window and document instead of $window and $document here is
13612// deliberate.  This service depends on the specific behavior of anchor nodes created by the
13613// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
13614// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
13615// doesn't know about mocked locations and resolves URLs to the real document - which is
13616// exactly the behavior needed here.  There is little value is mocking these out for this
13617// service.
13618var urlParsingNode = document.createElement("a");
13619var originUrl = urlResolve(window.location.href, true);
13620
13621
13622/**
13623 *
13624 * Implementation Notes for non-IE browsers
13625 * ----------------------------------------
13626 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
13627 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
13628 * URL will be resolved into an absolute URL in the context of the application document.
13629 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
13630 * properties are all populated to reflect the normalized URL.  This approach has wide
13631 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
13632 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
13633 *
13634 * Implementation Notes for IE
13635 * ---------------------------
13636 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
13637 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
13638 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
13639 * work around that by performing the parsing in a 2nd step by taking a previously normalized
13640 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
13641 * properties such as protocol, hostname, port, etc.
13642 *
13643 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
13644 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
13645 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
13646 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
13647 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
13648 * method and IE < 8 is unsupported.
13649 *
13650 * References:
13651 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
13652 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
13653 *   http://url.spec.whatwg.org/#urlutils
13654 *   https://github.com/angular/angular.js/pull/2902
13655 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
13656 *
13657 * @function
13658 * @param {string} url The URL to be parsed.
13659 * @description Normalizes and parses a URL.
13660 * @returns {object} Returns the normalized URL as a dictionary.
13661 *
13662 *   | member name   | Description    |
13663 *   |---------------|----------------|
13664 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
13665 *   | protocol      | The protocol including the trailing colon                              |
13666 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
13667 *   | search        | The search params, minus the question mark                             |
13668 *   | hash          | The hash string, minus the hash symbol
13669 *   | hostname      | The hostname
13670 *   | port          | The port, without ":"
13671 *   | pathname      | The pathname, beginning with "/"
13672 *
13673 */
13674function urlResolve(url, base) {
13675  var href = url;
13676
13677  if (msie) {
13678    // Normalize before parse.  Refer Implementation Notes on why this is
13679    // done in two steps on IE.
13680    urlParsingNode.setAttribute("href", href);
13681    href = urlParsingNode.href;
13682  }
13683
13684  urlParsingNode.setAttribute('href', href);
13685
13686  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
13687  return {
13688    href: urlParsingNode.href,
13689    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
13690    host: urlParsingNode.host,
13691    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
13692    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
13693    hostname: urlParsingNode.hostname,
13694    port: urlParsingNode.port,
13695    pathname: (urlParsingNode.pathname.charAt(0) === '/')
13696      ? urlParsingNode.pathname
13697      : '/' + urlParsingNode.pathname
13698  };
13699}
13700
13701/**
13702 * Parse a request URL and determine whether this is a same-origin request as the application document.
13703 *
13704 * @param {string|object} requestUrl The url of the request as a string that will be resolved
13705 * or a parsed URL object.
13706 * @returns {boolean} Whether the request is for the same origin as the application document.
13707 */
13708function urlIsSameOrigin(requestUrl) {
13709  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
13710  return (parsed.protocol === originUrl.protocol &&
13711          parsed.host === originUrl.host);
13712}
13713
13714/**
13715 * @ngdoc object
13716 * @name ng.$window
13717 *
13718 * @description
13719 * A reference to the browser's `window` object. While `window`
13720 * is globally available in JavaScript, it causes testability problems, because
13721 * it is a global variable. In angular we always refer to it through the
13722 * `$window` service, so it may be overridden, removed or mocked for testing.
13723 *
13724 * Expressions, like the one defined for the `ngClick` directive in the example
13725 * below, are evaluated with respect to the current scope.  Therefore, there is
13726 * no risk of inadvertently coding in a dependency on a global value in such an
13727 * expression.
13728 *
13729 * @example
13730   <doc:example>
13731     <doc:source>
13732       <script>
13733         function Ctrl($scope, $window) {
13734           $scope.greeting = 'Hello, World!';
13735           $scope.doGreeting = function(greeting) {
13736               $window.alert(greeting);
13737           };
13738         }
13739       </script>
13740       <div ng-controller="Ctrl">
13741         <input type="text" ng-model="greeting" />
13742         <button ng-click="doGreeting(greeting)">ALERT</button>
13743       </div>
13744     </doc:source>
13745     <doc:scenario>
13746      it('should display the greeting in the input box', function() {
13747       input('greeting').enter('Hello, E2E Tests');
13748       // If we click the button it will block the test runner
13749       // element(':button').click();
13750      });
13751     </doc:scenario>
13752   </doc:example>
13753 */
13754function $WindowProvider(){
13755  this.$get = valueFn(window);
13756}
13757
13758/**
13759 * @ngdoc object
13760 * @name ng.$filterProvider
13761 * @description
13762 *
13763 * Filters are just functions which transform input to an output. However filters need to be
13764 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
13765 * annotated with dependencies and is responsible for creating a filter function.
13766 *
13767 * <pre>
13768 *   // Filter registration
13769 *   function MyModule($provide, $filterProvider) {
13770 *     // create a service to demonstrate injection (not always needed)
13771 *     $provide.value('greet', function(name){
13772 *       return 'Hello ' + name + '!';
13773 *     });
13774 *
13775 *     // register a filter factory which uses the
13776 *     // greet service to demonstrate DI.
13777 *     $filterProvider.register('greet', function(greet){
13778 *       // return the filter function which uses the greet service
13779 *       // to generate salutation
13780 *       return function(text) {
13781 *         // filters need to be forgiving so check input validity
13782 *         return text && greet(text) || text;
13783 *       };
13784 *     });
13785 *   }
13786 * </pre>
13787 *
13788 * The filter function is registered with the `$injector` under the filter name suffix with
13789 * `Filter`.
13790 * 
13791 * <pre>
13792 *   it('should be the same instance', inject(
13793 *     function($filterProvider) {
13794 *       $filterProvider.register('reverse', function(){
13795 *         return ...;
13796 *       });
13797 *     },
13798 *     function($filter, reverseFilter) {
13799 *       expect($filter('reverse')).toBe(reverseFilter);
13800 *     });
13801 * </pre>
13802 *
13803 *
13804 * For more information about how angular filters work, and how to create your own filters, see
13805 * {@link guide/filter Filters} in the Angular Developer Guide.
13806 */
13807/**
13808 * @ngdoc method
13809 * @name ng.$filterProvider#register
13810 * @methodOf ng.$filterProvider
13811 * @description
13812 * Register filter factory function.
13813 *
13814 * @param {String} name Name of the filter.
13815 * @param {function} fn The filter factory function which is injectable.
13816 */
13817
13818
13819/**
13820 * @ngdoc function
13821 * @name ng.$filter
13822 * @function
13823 * @description
13824 * Filters are used for formatting data displayed to the user.
13825 *
13826 * The general syntax in templates is as follows:
13827 *
13828 *         {{ expression [| filter_name[:parameter_value] ... ] }}
13829 *
13830 * @param {String} name Name of the filter function to retrieve
13831 * @return {Function} the filter function
13832 */
13833$FilterProvider.$inject = ['$provide'];
13834function $FilterProvider($provide) {
13835  var suffix = 'Filter';
13836
13837  /**
13838   * @ngdoc function
13839   * @name ng.$controllerProvider#register
13840   * @methodOf ng.$controllerProvider
13841   * @param {string|Object} name Name of the filter function, or an object map of filters where
13842   *    the keys are the filter names and the values are the filter factories.
13843   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
13844   *    of the registered filter instances.
13845   */
13846  function register(name, factory) {
13847    if(isObject(name)) {
13848      var filters = {};
13849      forEach(name, function(filter, key) {
13850        filters[key] = register(key, filter);
13851      });
13852      return filters;
13853    } else {
13854      return $provide.factory(name + suffix, factory);
13855    }
13856  }
13857  this.register = register;
13858
13859  this.$get = ['$injector', function($injector) {
13860    return function(name) {
13861      return $injector.get(name + suffix);
13862    };
13863  }];
13864
13865  ////////////////////////////////////////
13866  
13867  /* global
13868    currencyFilter: false,
13869    dateFilter: false,
13870    filterFilter: false,
13871    jsonFilter: false,
13872    limitToFilter: false,
13873    lowercaseFilter: false,
13874    numberFilter: false,
13875    orderByFilter: false,
13876    uppercaseFilter: false,
13877  */
13878
13879  register('currency', currencyFilter);
13880  register('date', dateFilter);
13881  register('filter', filterFilter);
13882  register('json', jsonFilter);
13883  register('limitTo', limitToFilter);
13884  register('lowercase', lowercaseFilter);
13885  register('number', numberFilter);
13886  register('orderBy', orderByFilter);
13887  register('uppercase', uppercaseFilter);
13888}
13889
13890/**
13891 * @ngdoc filter
13892 * @name ng.filter:filter
13893 * @function
13894 *
13895 * @description
13896 * Selects a subset of items from `array` and returns it as a new array.
13897 *
13898 * @param {Array} array The source array.
13899 * @param {string|Object|function()} expression The predicate to be used for selecting items from
13900 *   `array`.
13901 *
13902 *   Can be one of:
13903 *
13904 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
13905 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
13906 *     will be returned. The predicate can be negated by prefixing the string with `!`.
13907 *
13908 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
13909 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
13910 *     which have property `name` containing "M" and property `phone` containing "1". A special
13911 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
13912 *     property of the object. That's equivalent to the simple substring match with a `string`
13913 *     as described above.
13914 *
13915 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
13916 *     called for each element of `array`. The final result is an array of those elements that
13917 *     the predicate returned true for.
13918 *
13919 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
13920 *     determining if the expected value (from the filter expression) and actual value (from
13921 *     the object in the array) should be considered a match.
13922 *
13923 *   Can be one of:
13924 *
13925 *     - `function(actual, expected)`:
13926 *       The function will be given the object value and the predicate value to compare and
13927 *       should return true if the item should be included in filtered result.
13928 *
13929 *     - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
13930 *       this is essentially strict comparison of expected and actual.
13931 *
13932 *     - `false|undefined`: A short hand for a function which will look for a substring match in case
13933 *       insensitive way.
13934 *
13935 * @example
13936   <doc:example>
13937     <doc:source>
13938       <div ng-init="friends = [{name:'John', phone:'555-1276'},
13939                                {name:'Mary', phone:'800-BIG-MARY'},
13940                                {name:'Mike', phone:'555-4321'},
13941                                {name:'Adam', phone:'555-5678'},
13942                                {name:'Julie', phone:'555-8765'},
13943                                {name:'Juliette', phone:'555-5678'}]"></div>
13944
13945       Search: <input ng-model="searchText">
13946       <table id="searchTextResults">
13947         <tr><th>Name</th><th>Phone</th></tr>
13948         <tr ng-repeat="friend in friends | filter:searchText">
13949           <td>{{friend.name}}</td>
13950           <td>{{friend.phone}}</td>
13951         </tr>
13952       </table>
13953       <hr>
13954       Any: <input ng-model="search.$"> <br>
13955       Name only <input ng-model="search.name"><br>
13956       Phone only <input ng-model="search.phone"><br>
13957       Equality <input type="checkbox" ng-model="strict"><br>
13958       <table id="searchObjResults">
13959         <tr><th>Name</th><th>Phone</th></tr>
13960         <tr ng-repeat="friend in friends | filter:search:strict">
13961           <td>{{friend.name}}</td>
13962           <td>{{friend.phone}}</td>
13963         </tr>
13964       </table>
13965     </doc:source>
13966     <doc:scenario>
13967       it('should search across all fields when filtering with a string', function() {
13968         input('searchText').enter('m');
13969         expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
13970           toEqual(['Mary', 'Mike', 'Adam']);
13971
13972         input('searchText').enter('76');
13973         expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
13974           toEqual(['John', 'Julie']);
13975       });
13976
13977       it('should search in specific fields when filtering with a predicate object', function() {
13978         input('search.$').enter('i');
13979         expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
13980           toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
13981       });
13982       it('should use a equal comparison when comparator is true', function() {
13983         input('search.name').enter('Julie');
13984         input('strict').check();
13985         expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
13986           toEqual(['Julie']);
13987       });
13988     </doc:scenario>
13989   </doc:example>
13990 */
13991function filterFilter() {
13992  return function(array, expression, comparator) {
13993    if (!isArray(array)) return array;
13994
13995    var comparatorType = typeof(comparator),
13996        predicates = [];
13997
13998    predicates.check = function(value) {
13999      for (var j = 0; j < predicates.length; j++) {
14000        if(!predicates[j](value)) {
14001          return false;
14002        }
14003      }
14004      return true;
14005    };
14006
14007    if (comparatorType !== 'function') {
14008      if (comparatorType === 'boolean' && comparator) {
14009        comparator = function(obj, text) {
14010          return angular.equals(obj, text);
14011        };
14012      } else {
14013        comparator = function(obj, text) {
14014          text = (''+text).toLowerCase();
14015          return (''+obj).toLowerCase().indexOf(text) > -1;
14016        };
14017      }
14018    }
14019
14020    var search = function(obj, text){
14021      if (typeof text == 'string' && text.charAt(0) === '!') {
14022        return !search(obj, text.substr(1));
14023      }
14024      switch (typeof obj) {
14025        case "boolean":
14026        case "number":
14027        case "string":
14028          return comparator(obj, text);
14029        case "object":
14030          switch (typeof text) {
14031            case "object":
14032              return comparator(obj, text);
14033            default:
14034              for ( var objKey in obj) {
14035                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14036                  return true;
14037                }
14038              }
14039              break;
14040          }
14041          return false;
14042        case "array":
14043          for ( var i = 0; i < obj.length; i++) {
14044            if (search(obj[i], text)) {
14045              return true;
14046            }
14047          }
14048          return false;
14049        default:
14050          return false;
14051      }
14052    };
14053    switch (typeof expression) {
14054      case "boolean":
14055      case "number":
14056      case "string":
14057        // Set up expression object and fall through
14058        expression = {$:expression};
14059        // jshint -W086
14060      case "object":
14061        // jshint +W086
14062        for (var key in expression) {
14063          (function(path) {
14064            if (typeof expression[path] == 'undefined') return;
14065            predicates.push(function(value) {
14066              return search(path == '$' ? value : getter(value, path), expression[path]);
14067            });
14068          })(key);
14069        }
14070        break;
14071      case 'function':
14072        predicates.push(expression);
14073        break;
14074      default:
14075        return array;
14076    }
14077    var filtered = [];
14078    for ( var j = 0; j < array.length; j++) {
14079      var value = array[j];
14080      if (predicates.check(value)) {
14081        filtered.push(value);
14082      }
14083    }
14084    return filtered;
14085  };
14086}
14087
14088/**
14089 * @ngdoc filter
14090 * @name ng.filter:currency
14091 * @function
14092 *
14093 * @description
14094 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14095 * symbol for current locale is used.
14096 *
14097 * @param {number} amount Input to filter.
14098 * @param {string=} symbol Currency symbol or identifier to be displayed.
14099 * @returns {string} Formatted number.
14100 *
14101 *
14102 * @example
14103   <doc:example>
14104     <doc:source>
14105       <script>
14106         function Ctrl($scope) {
14107           $scope.amount = 1234.56;
14108         }
14109       </script>
14110       <div ng-controller="Ctrl">
14111         <input type="number" ng-model="amount"> <br>
14112         default currency symbol ($): {{amount | currency}}<br>
14113         custom currency identifier (USD$): {{amount | currency:"USD$"}}
14114       </div>
14115     </doc:source>
14116     <doc:scenario>
14117       it('should init with 1234.56', function() {
14118         expect(binding('amount | currency')).toBe('$1,234.56');
14119         expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
14120       });
14121       it('should update', function() {
14122         input('amount').enter('-1234');
14123         expect(binding('amount | currency')).toBe('($1,234.00)');
14124         expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
14125       });
14126     </doc:scenario>
14127   </doc:example>
14128 */
14129currencyFilter.$inject = ['$locale'];
14130function currencyFilter($locale) {
14131  var formats = $locale.NUMBER_FORMATS;
14132  return function(amount, currencySymbol){
14133    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14134    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14135                replace(/\u00A4/g, currencySymbol);
14136  };
14137}
14138
14139/**
14140 * @ngdoc filter
14141 * @name ng.filter:number
14142 * @function
14143 *
14144 * @description
14145 * Formats a number as text.
14146 *
14147 * If the input is not a number an empty string is returned.
14148 *
14149 * @param {number|string} number Number to format.
14150 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14151 * If this is not provided then the fraction size is computed from the current locale's number
14152 * formatting pattern. In the case of the default locale, it will be 3.
14153 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14154 *
14155 * @example
14156   <doc:example>
14157     <doc:source>
14158       <script>
14159         function Ctrl($scope) {
14160           $scope.val = 1234.56789;
14161         }
14162       </script>
14163       <div ng-controller="Ctrl">
14164         Enter number: <input ng-model='val'><br>
14165         Default formatting: {{val | number}}<br>
14166         No fractions: {{val | number:0}}<br>
14167         Negative number: {{-val | number:4}}
14168       </div>
14169     </doc:source>
14170     <doc:scenario>
14171       it('should format numbers', function() {
14172         expect(binding('val | number')).toBe('1,234.568');
14173         expect(binding('val | number:0')).toBe('1,235');
14174         expect(binding('-val | number:4')).toBe('-1,234.5679');
14175       });
14176
14177       it('should update', function() {
14178         input('val').enter('3374.333');
14179         expect(binding('val | number')).toBe('3,374.333');
14180         expect(binding('val | number:0')).toBe('3,374');
14181         expect(binding('-val | number:4')).toBe('-3,374.3330');
14182       });
14183     </doc:scenario>
14184   </doc:example>
14185 */
14186
14187
14188numberFilter.$inject = ['$locale'];
14189function numberFilter($locale) {
14190  var formats = $locale.NUMBER_FORMATS;
14191  return function(number, fractionSize) {
14192    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14193      fractionSize);
14194  };
14195}
14196
14197var DECIMAL_SEP = '.';
14198function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14199  if (isNaN(number) || !isFinite(number)) return '';
14200
14201  var isNegative = number < 0;
14202  number = Math.abs(number);
14203  var numStr = number + '',
14204      formatedText = '',
14205      parts = [];
14206
14207  var hasExponent = false;
14208  if (numStr.indexOf('e') !== -1) {
14209    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14210    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14211      numStr = '0';
14212    } else {
14213      formatedText = numStr;
14214      hasExponent = true;
14215    }
14216  }
14217
14218  if (!hasExponent) {
14219    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14220
14221    // determine fractionSize if it is not specified
14222    if (isUndefined(fractionSize)) {
14223      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14224    }
14225
14226    var pow = Math.pow(10, fractionSize);
14227    number = Math.round(number * pow) / pow;
14228    var fraction = ('' + number).split(DECIMAL_SEP);
14229    var whole = fraction[0];
14230    fraction = fraction[1] || '';
14231
14232    var i, pos = 0,
14233        lgroup = pattern.lgSize,
14234        group = pattern.gSize;
14235
14236    if (whole.length >= (lgroup + group)) {
14237      pos = whole.length - lgroup;
14238      for (i = 0; i < pos; i++) {
14239        if ((pos - i)%group === 0 && i !== 0) {
14240          formatedText += groupSep;
14241        }
14242        formatedText += whole.charAt(i);
14243      }
14244    }
14245
14246    for (i = pos; i < whole.length; i++) {
14247      if ((whole.length - i)%lgroup === 0 && i !== 0) {
14248        formatedText += groupSep;
14249      }
14250      formatedText += whole.charAt(i);
14251    }
14252
14253    // format fraction part.
14254    while(fraction.length < fractionSize) {
14255      fraction += '0';
14256    }
14257
14258    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
14259  } else {
14260
14261    if (fractionSize > 0 && number > -1 && number < 1) {
14262      formatedText = number.toFixed(fractionSize);
14263    }
14264  }
14265
14266  parts.push(isNegative ? pattern.negPre : pattern.posPre);
14267  parts.push(formatedText);
14268  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
14269  return parts.join('');
14270}
14271
14272function padNumber(num, digits, trim) {
14273  var neg = '';
14274  if (num < 0) {
14275    neg =  '-';
14276    num = -num;
14277  }
14278  num = '' + num;
14279  while(num.length < digits) num = '0' + num;
14280  if (trim)
14281    num = num.substr(num.length - digits);
14282  return neg + num;
14283}
14284
14285
14286function dateGetter(name, size, offset, trim) {
14287  offset = offset || 0;
14288  return function(date) {
14289    var value = date['get' + name]();
14290    if (offset > 0 || value > -offset)
14291      value += offset;
14292    if (value === 0 && offset == -12 ) value = 12;
14293    return padNumber(value, size, trim);
14294  };
14295}
14296
14297function dateStrGetter(name, shortForm) {
14298  return function(date, formats) {
14299    var value = date['get' + name]();
14300    var get = uppercase(shortForm ? ('SHORT' + name) : name);
14301
14302    return formats[get][value];
14303  };
14304}
14305
14306function timeZoneGetter(date) {
14307  var zone = -1 * date.getTimezoneOffset();
14308  var paddedZone = (zone >= 0) ? "+" : "";
14309
14310  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
14311                padNumber(Math.abs(zone % 60), 2);
14312
14313  return paddedZone;
14314}
14315
14316function ampmGetter(date, formats) {
14317  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
14318}
14319
14320var DATE_FORMATS = {
14321  yyyy: dateGetter('FullYear', 4),
14322    yy: dateGetter('FullYear', 2, 0, true),
14323     y: dateGetter('FullYear', 1),
14324  MMMM: dateStrGetter('Month'),
14325   MMM: dateStrGetter('Month', true),
14326    MM: dateGetter('Month', 2, 1),
14327     M: dateGetter('Month', 1, 1),
14328    dd: dateGetter('Date', 2),
14329     d: dateGetter('Date', 1),
14330    HH: dateGetter('Hours', 2),
14331     H: dateGetter('Hours', 1),
14332    hh: dateGetter('Hours', 2, -12),
14333     h: dateGetter('Hours', 1, -12),
14334    mm: dateGetter('Minutes', 2),
14335     m: dateGetter('Minutes', 1),
14336    ss: dateGetter('Seconds', 2),
14337     s: dateGetter('Seconds', 1),
14338     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
14339     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
14340   sss: dateGetter('Milliseconds', 3),
14341  EEEE: dateStrGetter('Day'),
14342   EEE: dateStrGetter('Day', true),
14343     a: ampmGetter,
14344     Z: timeZoneGetter
14345};
14346
14347var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
14348    NUMBER_STRING = /^\-?\d+$/;
14349
14350/**
14351 * @ngdoc filter
14352 * @name ng.filter:date
14353 * @function
14354 *
14355 * @description
14356 *   Formats `date` to a string based on the requested `format`.
14357 *
14358 *   `format` string can be composed of the following elements:
14359 *
14360 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
14361 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
14362 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
14363 *   * `'MMMM'`: Month in year (January-December)
14364 *   * `'MMM'`: Month in year (Jan-Dec)
14365 *   * `'MM'`: Month in year, padded (01-12)
14366 *   * `'M'`: Month in year (1-12)
14367 *   * `'dd'`: Day in month, padded (01-31)
14368 *   * `'d'`: Day in month (1-31)
14369 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
14370 *   * `'EEE'`: Day in Week, (Sun-Sat)
14371 *   * `'HH'`: Hour in day, padded (00-23)
14372 *   * `'H'`: Hour in day (0-23)
14373 *   * `'hh'`: Hour in am/pm, padded (01-12)
14374 *   * `'h'`: Hour in am/pm, (1-12)
14375 *   * `'mm'`: Minute in hour, padded (00-59)
14376 *   * `'m'`: Minute in hour (0-59)
14377 *   * `'ss'`: Second in minute, padded (00-59)
14378 *   * `'s'`: Second in minute (0-59)
14379 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
14380 *   * `'a'`: am/pm marker
14381 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
14382 *
14383 *   `format` string can also be one of the following predefined
14384 *   {@link guide/i18n localizable formats}:
14385 *
14386 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
14387 *     (e.g. Sep 3, 2010 12:05:08 pm)
14388 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
14389 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
14390 *     (e.g. Friday, September 3, 2010)
14391 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
14392 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
14393 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
14394 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
14395 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
14396 *
14397 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
14398 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
14399 *   (e.g. `"h 'o''clock'"`).
14400 *
14401 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
14402 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
14403 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
14404 *    specified in the string input, the time is considered to be in the local timezone.
14405 * @param {string=} format Formatting rules (see Description). If not specified,
14406 *    `mediumDate` is used.
14407 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
14408 *
14409 * @example
14410   <doc:example>
14411     <doc:source>
14412       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
14413           {{1288323623006 | date:'medium'}}<br>
14414       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
14415          {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
14416       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
14417          {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
14418     </doc:source>
14419     <doc:scenario>
14420       it('should format date', function() {
14421         expect(binding("1288323623006 | date:'medium'")).
14422            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
14423         expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
14424            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
14425         expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
14426            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
14427       });
14428     </doc:scenario>
14429   </doc:example>
14430 */
14431dateFilter.$inject = ['$locale'];
14432function dateFilter($locale) {
14433
14434
14435  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
14436                     // 1        2       3         4          5          6          7          8  9     10      11
14437  function jsonStringToDate(string) {
14438    var match;
14439    if (match = string.match(R_ISO8601_STR)) {
14440      var date = new Date(0),
14441          tzHour = 0,
14442          tzMin  = 0,
14443          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
14444          timeSetter = match[8] ? date.setUTCHours : date.setHours;
14445
14446      if (match[9]) {
14447        tzHour = int(match[9] + match[10]);
14448        tzMin = int(match[9] + match[11]);
14449      }
14450      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
14451      var h = int(match[4]||0) - tzHour;
14452      var m = int(match[5]||0) - tzMin;
14453      var s = int(match[6]||0);
14454      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
14455      timeSetter.call(date, h, m, s, ms);
14456      return date;
14457    }
14458    return string;
14459  }
14460
14461
14462  return function(date, format) {
14463    var text = '',
14464        parts = [],
14465        fn, match;
14466
14467    format = format || 'mediumDate';
14468    format = $locale.DATETIME_FORMATS[format] || format;
14469    if (isString(date)) {
14470      if (NUMBER_STRING.test(date)) {
14471        date = int(date);
14472      } else {
14473        date = jsonStringToDate(date);
14474      }
14475    }
14476
14477    if (isNumber(date)) {
14478      date = new Date(date);
14479    }
14480
14481    if (!isDate(date)) {
14482      return date;
14483    }
14484
14485    while(format) {
14486      match = DATE_FORMATS_SPLIT.exec(format);
14487      if (match) {
14488        parts = concat(parts, match, 1);
14489        format = parts.pop();
14490      } else {
14491        parts.push(format);
14492        format = null;
14493      }
14494    }
14495
14496    forEach(parts, function(value){
14497      fn = DATE_FORMATS[value];
14498      text += fn ? fn(date, $locale.DATETIME_FORMATS)
14499                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
14500    });
14501
14502    return text;
14503  };
14504}
14505
14506
14507/**
14508 * @ngdoc filter
14509 * @name ng.filter:json
14510 * @function
14511 *
14512 * @description
14513 *   Allows you to convert a JavaScript object into JSON string.
14514 *
14515 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
14516 *   the binding is automatically converted to JSON.
14517 *
14518 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
14519 * @returns {string} JSON string.
14520 *
14521 *
14522 * @example:
14523   <doc:example>
14524     <doc:source>
14525       <pre>{{ {'name':'value'} | json }}</pre>
14526     </doc:source>
14527     <doc:scenario>
14528       it('should jsonify filtered objects', function() {
14529         expect(binding("{'name':'value'}")).toMatch(/\{\n  "name": ?"value"\n}/);
14530       });
14531     </doc:scenario>
14532   </doc:example>
14533 *
14534 */
14535function jsonFilter() {
14536  return function(object) {
14537    return toJson(object, true);
14538  };
14539}
14540
14541
14542/**
14543 * @ngdoc filter
14544 * @name ng.filter:lowercase
14545 * @function
14546 * @description
14547 * Converts string to lowercase.
14548 * @see angular.lowercase
14549 */
14550var lowercaseFilter = valueFn(lowercase);
14551
14552
14553/**
14554 * @ngdoc filter
14555 * @name ng.filter:uppercase
14556 * @function
14557 * @description
14558 * Converts string to uppercase.
14559 * @see angular.uppercase
14560 */
14561var uppercaseFilter = valueFn(uppercase);
14562
14563/**
14564 * @ngdoc function
14565 * @name ng.filter:limitTo
14566 * @function
14567 *
14568 * @description
14569 * Creates a new array or string containing only a specified number of elements. The elements
14570 * are taken from either the beginning or the end of the source array or string, as specified by
14571 * the value and sign (positive or negative) of `limit`.
14572 *
14573 * @param {Array|string} input Source array or string to be limited.
14574 * @param {string|number} limit The length of the returned array or string. If the `limit` number 
14575 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
14576 *     If the number is negative, `limit` number  of items from the end of the source array/string 
14577 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
14578 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
14579 *     had less than `limit` elements.
14580 *
14581 * @example
14582   <doc:example>
14583     <doc:source>
14584       <script>
14585         function Ctrl($scope) {
14586           $scope.numbers = [1,2,3,4,5,6,7,8,9];
14587           $scope.letters = "abcdefghi";
14588           $scope.numLimit = 3;
14589           $scope.letterLimit = 3;
14590         }
14591       </script>
14592       <div ng-controller="Ctrl">
14593         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
14594         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
14595         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
14596         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
14597       </div>
14598     </doc:source>
14599     <doc:scenario>
14600       it('should limit the number array to first three items', function() {
14601         expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
14602         expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
14603         expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
14604         expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
14605       });
14606
14607       it('should update the output when -3 is entered', function() {
14608         input('numLimit').enter(-3);
14609         input('letterLimit').enter(-3);
14610         expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
14611         expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
14612       });
14613
14614       it('should not exceed the maximum size of input array', function() {
14615         input('numLimit').enter(100);
14616         input('letterLimit').enter(100);
14617         expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
14618         expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
14619       });
14620     </doc:scenario>
14621   </doc:example>
14622 */
14623function limitToFilter(){
14624  return function(input, limit) {
14625    if (!isArray(input) && !isString(input)) return input;
14626    
14627    limit = int(limit);
14628
14629    if (isString(input)) {
14630      //NaN check on limit
14631      if (limit) {
14632        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
14633      } else {
14634        return "";
14635      }
14636    }
14637
14638    var out = [],
14639      i, n;
14640
14641    // if abs(limit) exceeds maximum length, trim it
14642    if (limit > input.length)
14643      limit = input.length;
14644    else if (limit < -input.length)
14645      limit = -input.length;
14646
14647    if (limit > 0) {
14648      i = 0;
14649      n = limit;
14650    } else {
14651      i = input.length + limit;
14652      n = input.length;
14653    }
14654
14655    for (; i<n; i++) {
14656      out.push(input[i]);
14657    }
14658
14659    return out;
14660  };
14661}
14662
14663/**
14664 * @ngdoc function
14665 * @name ng.filter:orderBy
14666 * @function
14667 *
14668 * @description
14669 * Orders a specified `array` by the `expression` predicate.
14670 *
14671 * @param {Array} array The array to sort.
14672 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
14673 *    used by the comparator to determine the order of elements.
14674 *
14675 *    Can be one of:
14676 *
14677 *    - `function`: Getter function. The result of this function will be sorted using the
14678 *      `<`, `=`, `>` operator.
14679 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
14680 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
14681 *      ascending or descending sort order (for example, +name or -name).
14682 *    - `Array`: An array of function or string predicates. The first predicate in the array
14683 *      is used for sorting, but when two items are equivalent, the next predicate is used.
14684 *
14685 * @param {boolean=} reverse Reverse the order the array.
14686 * @returns {Array} Sorted copy of the source array.
14687 *
14688 * @example
14689   <doc:example>
14690     <doc:source>
14691       <script>
14692         function Ctrl($scope) {
14693           $scope.friends =
14694               [{name:'John', phone:'555-1212', age:10},
14695                {name:'Mary', phone:'555-9876', age:19},
14696                {name:'Mike', phone:'555-4321', age:21},
14697                {name:'Adam', phone:'555-5678', age:35},
14698                {name:'Julie', phone:'555-8765', age:29}]
14699           $scope.predicate = '-age';
14700         }
14701       </script>
14702       <div ng-controller="Ctrl">
14703         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
14704         <hr/>
14705         [ <a href="" ng-click="predicate=''">unsorted</a> ]
14706         <table class="friend">
14707           <tr>
14708             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
14709                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
14710             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
14711             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
14712           </tr>
14713           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
14714             <td>{{friend.name}}</td>
14715             <td>{{friend.phone}}</td>
14716             <td>{{friend.age}}</td>
14717           </tr>
14718         </table>
14719       </div>
14720     </doc:source>
14721     <doc:scenario>
14722       it('should be reverse ordered by aged', function() {
14723         expect(binding('predicate')).toBe('-age');
14724         expect(repeater('table.friend', 'friend in friends').column('friend.age')).
14725           toEqual(['35', '29', '21', '19', '10']);
14726         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14727           toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
14728       });
14729
14730       it('should reorder the table when user selects different predicate', function() {
14731         element('.doc-example-live a:contains("Name")').click();
14732         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14733           toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
14734         expect(repeater('table.friend', 'friend in friends').column('friend.age')).
14735           toEqual(['35', '10', '29', '19', '21']);
14736
14737         element('.doc-example-live a:contains("Phone")').click();
14738         expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
14739           toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
14740         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
14741           toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
14742       });
14743     </doc:scenario>
14744   </doc:example>
14745 */
14746orderByFilter.$inject = ['$parse'];
14747function orderByFilter($parse){
14748  return function(array, sortPredicate, reverseOrder) {
14749    if (!isArray(array)) return array;
14750    if (!sortPredicate) return array;
14751    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
14752    sortPredicate = map(sortPredicate, function(predicate){
14753      var descending = false, get = predicate || identity;
14754      if (isString(predicate)) {
14755        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
14756          descending = predicate.charAt(0) == '-';
14757          predicate = predicate.substring(1);
14758        }
14759        get = $parse(predicate);
14760      }
14761      return reverseComparator(function(a,b){
14762        return compare(get(a),get(b));
14763      }, descending);
14764    });
14765    var arrayCopy = [];
14766    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
14767    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
14768
14769    function comparator(o1, o2){
14770      for ( var i = 0; i < sortPredicate.length; i++) {
14771        var comp = sortPredicate[i](o1, o2);
14772        if (comp !== 0) return comp;
14773      }
14774      return 0;
14775    }
14776    function reverseComparator(comp, descending) {
14777      return toBoolean(descending)
14778          ? function(a,b){return comp(b,a);}
14779          : comp;
14780    }
14781    function compare(v1, v2){
14782      var t1 = typeof v1;
14783      var t2 = typeof v2;
14784      if (t1 == t2) {
14785        if (t1 == "string") {
14786           v1 = v1.toLowerCase();
14787           v2 = v2.toLowerCase();
14788        }
14789        if (v1 === v2) return 0;
14790        return v1 < v2 ? -1 : 1;
14791      } else {
14792        return t1 < t2 ? -1 : 1;
14793      }
14794    }
14795  };
14796}
14797
14798function ngDirective(directive) {
14799  if (isFunction(directive)) {
14800    directive = {
14801      link: directive
14802    };
14803  }
14804  directive.restrict = directive.restrict || 'AC';
14805  return valueFn(directive);
14806}
14807
14808/**
14809 * @ngdoc directive
14810 * @name ng.directive:a
14811 * @restrict E
14812 *
14813 * @description
14814 * Modifies the default behavior of the html A tag so that the default action is prevented when
14815 * the href attribute is empty.
14816 *
14817 * This change permits the easy creation of action links with the `ngClick` directive
14818 * without changing the location or causing page reloads, e.g.:
14819 * `<a href="" ng-click="list.addItem()">Add Item</a>`
14820 */
14821var htmlAnchorDirective = valueFn({
14822  restrict: 'E',
14823  compile: function(element, attr) {
14824
14825    if (msie <= 8) {
14826
14827      // turn <a href ng-click="..">link</a> into a stylable link in IE
14828      // but only if it doesn't have name attribute, in which case it's an anchor
14829      if (!attr.href && !attr.name) {
14830        attr.$set('href', '');
14831      }
14832
14833      // add a comment node to anchors to workaround IE bug that causes element content to be reset
14834      // to new attribute content if attribute is updated with value containing @ and element also
14835      // contains value with @
14836      // see issue #1949
14837      element.append(document.createComment('IE fix'));
14838    }
14839
14840    if (!attr.href && !attr.xlinkHref && !attr.name) {
14841      return function(scope, element) {
14842        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
14843        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
14844                   'xlink:href' : 'href';
14845        element.on('click', function(event){
14846          // if we have no href url, then don't navigate anywhere.
14847          if (!element.attr(href)) {
14848            event.preventDefault();
14849          }
14850        });
14851      };
14852    }
14853  }
14854});
14855
14856/**
14857 * @ngdoc directive
14858 * @name ng.directive:ngHref
14859 * @restrict A
14860 * @priority 99
14861 *
14862 * @description
14863 * Using Angular markup like `{{hash}}` in an href attribute will
14864 * make the link go to the wrong URL if the user clicks it before
14865 * Angular has a chance to replace the `{{hash}}
14865` markup with its
14866 * value. Until Angular replaces the markup the link will be broken
14867 * and will most likely return a 404 error.
14868 *
14869 * The `ngHref` directive solves this problem.
14870 *
14871 * The wrong way to write it:
14872 * <pre>
14873 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
14874 * </pre>
14875 *
14876 * The correct way to write it:
14877 * <pre>
14878 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
14879 * </pre>
14880 *
14881 * @element A
14882 * @param {template} ngHref any string which can contain `{{}}` markup.
14883 *
14884 * @example
14885 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
14886 * in links and their different behaviors:
14887    <doc:example>
14888      <doc:source>
14889        <input ng-model="value" /><br />
14890        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
14891        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
14892        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
14893        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
14894        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
14895        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
14896      </doc:source>
14897      <doc:scenario>
14898        it('should execute ng-click but not reload when href without value', function() {
14899          element('#link-1').click();
14900          expect(input('value').val()).toEqual('1');
14901          expect(element('#link-1').attr('href')).toBe("");
14902        });
14903
14904        it('should execute ng-click but not reload when href empty string', function() {
14905          element('#link-2').click();
14906          expect(input('value').val()).toEqual('2');
14907          expect(element('#link-2').attr('href')).toBe("");
14908        });
14909
14910        it('should execute ng-click and change url when ng-href specified', function() {
14911          expect(element('#link-3').attr('href')).toBe("/123");
14912
14913          element('#link-3').click();
14914          expect(browser().window().path()).toEqual('/123');
14915        });
14916
14917        it('should execute ng-click but not reload when href empty string and name specified', function() {
14918          element('#link-4').click();
14919          expect(input('value').val()).toEqual('4');
14920          expect(element('#link-4').attr('href')).toBe('');
14921        });
14922
14923        it('should execute ng-click but not reload when no href but name specified', function() {
14924          element('#link-5').click();
14925          expect(input('value').val()).toEqual('5');
14926          expect(element('#link-5').attr('href')).toBe(undefined);
14927        });
14928
14929        it('should only change url when only ng-href', function() {
14930          input('value').enter('6');
14931          expect(element('#link-6').attr('href')).toBe('6');
14932
14933          element('#link-6').click();
14934          expect(browser().location().url()).toEqual('/6');
14935        });
14936      </doc:scenario>
14937    </doc:example>
14938 */
14939
14940/**
14941 * @ngdoc directive
14942 * @name ng.directive:ngSrc
14943 * @restrict A
14944 * @priority 99
14945 *
14946 * @description
14947 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
14948 * work right: The browser will fetch from the URL with the literal
14949 * text `{{hash}}` until Angular replaces the expression inside
14950 * `{{hash}}`. The `ngSrc` directive solves this problem.
14951 *
14952 * The buggy way to write it:
14953 * <pre>
14954 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
14955 * </pre>
14956 *
14957 * The correct way to write it:
14958 * <pre>
14959 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
14960 * </pre>
14961 *
14962 * @element IMG
14963 * @param {template} ngSrc any string which can contain `{{}}` markup.
14964 */
14965
14966/**
14967 * @ngdoc directive
14968 * @name ng.directive:ngSrcset
14969 * @restrict A
14970 * @priority 99
14971 *
14972 * @description
14973 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
14974 * work right: The browser will fetch from the URL with the literal
14975 * text `{{hash}}` until Angular replaces the expression inside
14976 * `{{hash}}`. The `ngSrcset` directive solves this problem.
14977 *
14978 * The buggy way to write it:
14979 * <pre>
14980 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
14981 * </pre>
14982 *
14983 * The correct way to write it:
14984 * <pre>
14985 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
14986 * </pre>
14987 *
14988 * @element IMG
14989 * @param {template} ngSrcset any string which can contain `{{}}` markup.
14990 */
14991
14992/**
14993 * @ngdoc directive
14994 * @name ng.directive:ngDisabled
14995 * @restrict A
14996 * @priority 100
14997 *
14998 * @description
14999 *
15000 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15001 * <pre>
15002 * <div ng-init="scope = { isDisabled: false }">
15003 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15004 * </div>
15005 * </pre>
15006 *
15007 * The HTML specification does not require browsers to preserve the values of boolean attributes
15008 * such as disabled. (Their presence means true and their absence means false.)
15009 * If we put an Angular interpolation expression into such an attribute then the
15010 * binding information would be lost when the browser removes the attribute.
15011 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15012 * This complementary directive is not removed by the browser and so provides
15013 * a permanent reliable place to store the binding information.
15014 *
15015 * @example
15016    <doc:example>
15017      <doc:source>
15018        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15019        <button ng-model="button" ng-disabled="checked">Button</button>
15020      </doc:source>
15021      <doc:scenario>
15022        it('should toggle button', function() {
15023          expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
15024          input('checked').check();
15025          expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
15026        });
15027      </doc:scenario>
15028    </doc:example>
15029 *
15030 * @element INPUT
15031 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, 
15032 *     then special attribute "disabled" will be set on the element
15033 */
15034
15035
15036/**
15037 * @ngdoc directive
15038 * @name ng.directive:ngChecked
15039 * @restrict A
15040 * @priority 100
15041 *
15042 * @description
15043 * The HTML specification does not require browsers to preserve the values of boolean attributes
15044 * such as checked. (Their presence means true and their absence means false.)
15045 * If we put an Angular interpolation expression into such an attribute then the
15046 * binding information would be lost when the browser removes the attribute.
15047 * The `ngChecked` directive solves this problem for the `checked` attribute.
15048 * This complementary directive is not removed by the browser and so provides
15049 * a permanent reliable place to store the binding information.
15050 * @example
15051    <doc:example>
15052      <doc:source>
15053        Check me to check both: <input type="checkbox" ng-model="master"><br/>
15054        <input id="checkSlave" type="checkbox" ng-checked="master">
15055      </doc:source>
15056      <doc:scenario>
15057        it('should check both checkBoxes', function() {
15058          expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
15059          input('master').check();
15060          expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
15061        });
15062      </doc:scenario>
15063    </doc:example>
15064 *
15065 * @element INPUT
15066 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, 
15067 *     then special attribute "checked" will be set on the element
15068 */
15069
15070
15071/**
15072 * @ngdoc directive
15073 * @name ng.directive:ngReadonly
15074 * @restrict A
15075 * @priority 100
15076 *
15077 * @description
15078 * The HTML specification does not require browsers to preserve the values of boolean attributes
15079 * such as readonly. (Their presence means true and their absence means false.)
15080 * If we put an Angular interpolation expression into such an attribute then the
15081 * binding information would be lost when the browser removes the attribute.
15082 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15083 * This complementary directive is not removed by the browser and so provides
15084 * a permanent reliable place to store the binding information.
15085 * @example
15086    <doc:example>
15087      <doc:source>
15088        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15089        <input type="text" ng-readonly="checked" value="I'm Angular"/>
15090      </doc:source>
15091      <doc:scenario>
15092        it('should toggle readonly attr', function() {
15093          expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
15094          input('checked').check();
15095          expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
15096        });
15097      </doc:scenario>
15098    </doc:example>
15099 *
15100 * @element INPUT
15101 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, 
15102 *     then special attribute "readonly" will be set on the element
15103 */
15104
15105
15106/**
15107 * @ngdoc directive
15108 * @name ng.directive:ngSelected
15109 * @restrict A
15110 * @priority 100
15111 *
15112 * @description
15113 * The HTML specification does not require browsers to preserve the values of boolean attributes
15114 * such as selected. (Their presence means true and their absence means false.)
15115 * If we put an Angular interpolation expression into such an attribute then the
15116 * binding information would be lost when the browser removes the attribute.
15117 * The `ngSelected` directive solves this problem for the `selected` atttribute.
15118 * This complementary directive is not removed by the browser and so provides
15119 * a permanent reliable place to store the binding information.
15120 * 
15121 * @example
15122    <doc:example>
15123      <doc:source>
15124        Check me to select: <input type="checkbox" ng-model="selected"><br/>
15125        <select>
15126          <option>Hello!</option>
15127          <option id="greet" ng-selected="selected">Greetings!</option>
15128        </select>
15129      </doc:source>
15130      <doc:scenario>
15131        it('should select Greetings!', function() {
15132          expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
15133          input('selected').check();
15134          expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
15135        });
15136      </doc:scenario>
15137    </doc:example>
15138 *
15139 * @element OPTION
15140 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, 
15141 *     then special attribute "selected" will be set on the element
15142 */
15143
15144/**
15145 * @ngdoc directive
15146 * @name ng.directive:ngOpen
15147 * @restrict A
15148 * @priority 100
15149 *
15150 * @description
15151 * The HTML specification does not require browsers to preserve the values of boolean attributes
15152 * such as open. (Their presence means true and their absence means false.)
15153 * If we put an Angular interpolation expression into such an attribute then the
15154 * binding information would be lost when the browser removes the attribute.
15155 * The `ngOpen` directive solves this problem for the `open` attribute.
15156 * This complementary directive is not removed by the browser and so provides
15157 * a permanent reliable place to store the binding information.
15158 * @example
15159     <doc:example>
15160       <doc:source>
15161         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15162         <details id="details" ng-open="open">
15163            <summary>Show/Hide me</summary>
15164         </details>
15165       </doc:source>
15166       <doc:scenario>
15167         it('should toggle open', function() {
15168           expect(element('#details').prop('open')).toBeFalsy();
15169           input('open').check();
15170           expect(element('#details').prop('open')).toBeTruthy();
15171         });
15172       </doc:scenario>
15173     </doc:example>
15174 *
15175 * @element DETAILS
15176 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, 
15177 *     then special attribute "open" will be set on the element
15178 */
15179
15180var ngAttributeAliasDirectives = {};
15181
15182
15183// boolean attrs are evaluated
15184forEach(BOOLEAN_ATTR, function(propName, attrName) {
15185  // binding to multiple is not supported
15186  if (propName == "multiple") return;
15187
15188  var normalized = directiveNormalize('ng-' + attrName);
15189  ngAttributeAliasDirectives[normalized] = function() {
15190    return {
15191      priority: 100,
15192      link: function(scope, element, attr) {
15193        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
15194          attr.$set(attrName, !!value);
15195        });
15196      }
15197    };
15198  };
15199});
15200
15201
15202// ng-src, ng-srcset, ng-href are interpolated
15203forEach(['src', 'srcset', 'href'], function(attrName) {
15204  var normalized = directiveNormalize('ng-' + attrName);
15205  ngAttributeAliasDirectives[normalized] = function() {
15206    return {
15207      priority: 99, // it needs to run after the attributes are interpolated
15208      link: function(scope, element, attr) {
15209        attr.$observe(normalized, function(value) {
15210          if (!value)
15211             return;
15212
15213          attr.$set(attrName, value);
15214
15215          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
15216          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
15217          // to set the property as well to achieve the desired effect.
15218          // we use attr[attrName] value since $set can sanitize the url.
15219          if (msie) element.prop(attrName, attr[attrName]);
15220        });
15221      }
15222    };
15223  };
15224});
15225
15226/* global -nullFormCtrl */
15227var nullFormCtrl = {
15228  $addControl: noop,
15229  $removeControl: noop,
15230  $setValidity: noop,
15231  $setDirty: noop,
15232  $setPristine: noop
15233};
15234
15235/**
15236 * @ngdoc object
15237 * @name ng.directive:form.FormController
15238 *
15239 * @property {boolean} $pristine True if user has not interacted with the form yet.
15240 * @property {boolean} $dirty True if user has already interacted with the form.
15241 * @property {boolean} $valid True if all of the containing forms and controls are valid.
15242 * @property {boolean} $invalid True if at least one containing control or form is invalid.
15243 *
15244 * @property {Object} $error Is an object hash, containing references to all invalid controls or
15245 *  forms, where:
15246 *
15247 *  - keys are validation tokens (error names),
15248 *  - values are arrays of controls or forms that are invalid for given error name.
15249 *
15250 *
15251 *  Built-in validation tokens:
15252 *
15253 *  - `email`
15254 *  - `max`
15255 *  - `maxlength`
15256 *  - `min`
15257 *  - `minlength`
15258 *  - `number`
15259 *  - `pattern`
15260 *  - `required`
15261 *  - `url`
15262 * 
15263 * @description
15264 * `FormController` keeps track of all its controls and nested forms as well as state of them,
15265 * such as being valid/invalid or dirty/pristine.
15266 *
15267 * Each {@link ng.directive:form form} directive creates an instance
15268 * of `FormController`.
15269 *
15270 */
15271//asks for $scope to fool the BC controller module
15272FormController.$inject = ['$element', '$attrs', '$scope'];
15273function FormController(element, attrs) {
15274  var form = this,
15275      parentForm = element.parent().controller('form') || nullFormCtrl,
15276      invalidCount = 0, // used to easily determine if we are valid
15277      errors = form.$error = {},
15278      controls = [];
15279
15280  // init state
15281  form.$name = attrs.name || attrs.ngForm;
15282  form.$dirty = false;
15283  form.$pristine = true;
15284  form.$valid = true;
15285  form.$invalid = false;
15286
15287  parentForm.$addControl(form);
15288
15289  // Setup initial state of the control
15290  element.addClass(PRISTINE_CLASS);
15291  toggleValidCss(true);
15292
15293  // convenience method for easy toggling of classes
15294  function toggleValidCss(isValid, validationErrorKey) {
15295    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
15296    element.
15297      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
15298      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
15299  }
15300
15301  /**
15302   * @ngdoc function
15303   * @name ng.directive:form.FormController#$addControl
15304   * @methodOf ng.directive:form.FormController
15305   *
15306   * @description
15307   * Register a control with the form.
15308   *
15309   * Input elements using ngModelController do this automatically when they are linked.
15310   */
15311  form.$addControl = function(control) {
15312    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
15313    // and not added to the scope.  Now we throw an error.
15314    assertNotHasOwnProperty(control.$name, 'input');
15315    controls.push(control);
15316
15317    if (control.$name) {
15318      form[control.$name] = control;
15319    }
15320  };
15321
15322  /**
15323   * @ngdoc function
15324   * @name ng.directive:form.FormController#$removeControl
15325   * @methodOf ng.directive:form.FormController
15326   *
15327   * @description
15328   * Deregister a control from the form.
15329   *
15330   * Input elements using ngModelController do this automatically when they are destroyed.
15331   */
15332  form.$removeControl = function(control) {
15333    if (control.$name && form[control.$name] === control) {
15334      delete form[control.$name];
15335    }
15336    forEach(errors, function(queue, validationToken) {
15337      form.$setValidity(validationToken, true, control);
15338    });
15339
15340    arrayRemove(controls, control);
15341  };
15342
15343  /**
15344   * @ngdoc function
15345   * @name ng.directive:form.FormController#$setValidity
15346   * @methodOf ng.directive:form.FormController
15347   *
15348   * @description
15349   * Sets the validity of a form control.
15350   *
15351   * This method will also propagate to parent forms.
15352   */
15353  form.$setValidity = function(validationToken, isValid, control) {
15354    var queue = errors[validationToken];
15355
15356    if (isValid) {
15357      if (queue) {
15358        arrayRemove(queue, control);
15359        if (!queue.length) {
15360          invalidCount--;
15361          if (!invalidCount) {
15362            toggleValidCss(isValid);
15363            form.$valid = true;
15364            form.$invalid = false;
15365          }
15366          errors[validationToken] = false;
15367          toggleValidCss(true, validationToken);
15368          parentForm.$setValidity(validationToken, true, form);
15369        }
15370      }
15371
15372    } else {
15373      if (!invalidCount) {
15374        toggleValidCss(isValid);
15375      }
15376      if (queue) {
15377        if (includes(queue, control)) return;
15378      } else {
15379        errors[validationToken] = queue = [];
15380        invalidCount++;
15381        toggleValidCss(false, validationToken);
15382        parentForm.$setValidity(validationToken, false, form);
15383      }
15384      queue.push(control);
15385
15386      form.$valid = false;
15387      form.$invalid = true;
15388    }
15389  };
15390
15391  /**
15392   * @ngdoc function
15393   * @name ng.directive:form.FormController#$setDirty
15394   * @methodOf ng.directive:form.FormController
15395   *
15396   * @description
15397   * Sets the form to a dirty state.
15398   *
15399   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
15400   * state (ng-dirty class). This method will also propagate to parent forms.
15401   */
15402  form.$setDirty = function() {
15403    element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
15404    form.$dirty = true;
15405    form.$pristine = false;
15406    parentForm.$setDirty();
15407  };
15408
15409  /**
15410   * @ngdoc function
15411   * @name ng.directive:form.FormController#$setPristine
15412   * @methodOf ng.directive:form.FormController
15413   *
15414   * @description
15415   * Sets the form to its pristine state.
15416   *
15417   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
15418   * state (ng-pristine class). This method will also propagate to all the controls contained
15419   * in this form.
15420   *
15421   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
15422   * saving or resetting it.
15423   */
15424  form.$setPristine = function () {
15425    element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
15426    form.$dirty = false;
15427    form.$pristine = true;
15428    forEach(controls, function(control) {
15429      control.$setPristine();
15430    });
15431  };
15432}
15433
15434
15435/**
15436 * @ngdoc directive
15437 * @name ng.directive:ngForm
15438 * @restrict EAC
15439 *
15440 * @description
15441 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
15442 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
15443 * sub-group of controls needs to be determined.
15444 *
15445 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
15446 *                       related scope, under this name.
15447 *
15448 */
15449
15450 /**
15451 * @ngdoc directive
15452 * @name ng.directive:form
15453 * @restrict E
15454 *
15455 * @description
15456 * Directive that instantiates
15457 * {@link ng.directive:form.FormController FormController}.
15458 *
15459 * If the `name` attribute is specified, the form controller is published onto the current scope under
15460 * this name.
15461 *
15462 * # Alias: {@link ng.directive:ngForm `ngForm`}
15463 *
15464 * In Angular forms can be nested. This means that the outer form is valid when all of the child
15465 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
15466 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
15467 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
15468 * using Angular validation directives in forms that are dynamically generated using the
15469 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
15470 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
15471 * `ngForm` directive and nest these in an outer `form` element.
15472 *
15473 *
15474 * # CSS classes
15475 *  - `ng-valid` is set if the form is valid.
15476 *  - `ng-invalid` is set if the form is invalid.
15477 *  - `ng-pristine` is set if the form is pristine.
15478 *  - `ng-dirty` is set if the form is dirty.
15479 *
15480 *
15481 * # Submitting a form and preventing the default action
15482 *
15483 * Since the role of forms in client-side Angular applications is different than in classical
15484 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
15485 * page reload that sends the data to the server. Instead some javascript logic should be triggered
15486 * to handle the form submission in an application-specific way.
15487 *
15488 * For this reason, Angular prevents the default action (form submission to the server) unless the
15489 * `<form>` element has an `action` attribute specified.
15490 *
15491 * You can use one of the following two ways to specify what javascript method should be called when
15492 * a form is submitted:
15493 *
15494 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
15495 * - {@link ng.directive:ngClick ngClick} directive on the first
15496  *  button or input field of type submit (input[type=submit])
15497 *
15498 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
15499 * or {@link ng.directive:ngClick ngClick} directives.
15500 * This is because of the following form submission rules in the HTML specification:
15501 *
15502 * - If a form has only one input field then hitting enter in this field triggers form submit
15503 * (`ngSubmit`)
15504 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
15505 * doesn't trigger submit
15506 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
15507 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
15508 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
15509 *
15510 * @param {string=} name Name of the form. If specified, the form controller will be published into
15511 *                       related scope, under this name.
15512 *
15513 * @example
15514    <doc:example>
15515      <doc:source>
15516       <script>
15517         function Ctrl($scope) {
15518           $scope.userType = 'guest';
15519         }
15520       </script>
15521       <form name="myForm" ng-controller="Ctrl">
15522         userType: <input name="input" ng-model="userType" required>
15523         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
15524         <tt>userType = {{userType}}</tt><br>
15525         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
15526         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
15527         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
15528         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
15529        </form>
15530      </doc:source>
15531      <doc:scenario>
15532        it('should initialize to model', function() {
15533         expect(binding('userType')).toEqual('guest');
15534         expect(binding('myForm.input.$valid')).toEqual('true');
15535        });
15536
15537        it('should be invalid if empty', function() {
15538         input('userType').enter('');
15539         expect(binding('userType')).toEqual('');
15540         expect(binding('myForm.input.$valid')).toEqual('false');
15541        });
15542      </doc:scenario>
15543    </doc:example>
15544 */
15545var formDirectiveFactory = function(isNgForm) {
15546  return ['$timeout', function($timeout) {
15547    var formDirective = {
15548      name: 'form',
15549      restrict: isNgForm ? 'EAC' : 'E',
15550      controller: FormController,
15551      compile: function() {
15552        return {
15553          pre: function(scope, formElement, attr, controller) {
15554            if (!attr.action) {
15555              // we can't use jq events because if a form is destroyed during submission the default
15556              // action is not prevented. see #1238
15557              //
15558              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
15559              // page reload if the form was destroyed by submission of the form via a click handler
15560              // on a button in the form. Looks like an IE9 specific bug.
15561              var preventDefaultListener = function(event) {
15562                event.preventDefault
15563                  ? event.preventDefault()
15564                  : event.returnValue = false; // IE
15565              };
15566
15567              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
15568
15569              // unregister the preventDefault listener so that we don't not leak memory but in a
15570              // way that will achieve the prevention of the default action.
15571              formElement.on('$destroy', function() {
15572                $timeout(function() {
15573                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
15574                }, 0, false);
15575              });
15576            }
15577
15578            var parentFormCtrl = formElement.parent().controller('form'),
15579                alias = attr.name || attr.ngForm;
15580
15581            if (alias) {
15582              setter(scope, alias, controller, alias);
15583            }
15584            if (parentFormCtrl) {
15585              formElement.on('$destroy', function() {
15586                parentFormCtrl.$removeControl(controller);
15587                if (alias) {
15588                  setter(scope, alias, undefined, alias);
15589                }
15590                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
15591              });
15592            }
15593          }
15594        };
15595      }
15596    };
15597
15598    return formDirective;
15599  }];
15600};
15601
15602var formDirective = formDirectiveFactory();
15603var ngFormDirective = formDirectiveFactory(true);
15604
15605/* global
15606
15607    -VALID_CLASS,
15608    -INVALID_CLASS,
15609    -PRISTINE_CLASS,
15610    -DIRTY_CLASS
15611*/
15612
15613var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
15614var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
15615var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
15616
15617var inputType = {
15618
15619  /**
15620   * @ngdoc inputType
15621   * @name ng.directive:input.text
15622   *
15623   * @description
15624   * Standard HTML text input with angular data binding.
15625   *
15626   * @param {string} ngModel Assignable angular expression to data-bind to.
15627   * @param {string=} name Property name of the form under which the control is published.
15628   * @param {string=} required Adds `required` validation error key if the value is not entered.
15629   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15630   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15631   *    `required` when you want to data-bind to the `required` attribute.
15632   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15633   *    minlength.
15634   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15635   *    maxlength.
15636   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15637   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15638   *    patterns defined as scope expressions.
15639   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15640   *    interaction with the input element.
15641   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
15642   *
15643   * @example
15644      <doc:example>
15645        <doc:source>
15646         <script>
15647           function Ctrl($scope) {
15648             $scope.text = 'guest';
15649             $scope.word = /^\s*\w*\s*$/;
15650           }
15651         </script>
15652         <form name="myForm" ng-controller="Ctrl">
15653           Single word: <input type="text" name="input" ng-model="text"
15654                               ng-pattern="word" required ng-trim="false">
15655           <span class="error" ng-show="myForm.input.$error.required">
15656             Required!</span>
15657           <span class="error" ng-show="myForm.input.$error.pattern">
15658             Single word only!</span>
15659
15660           <tt>text = {{text}}</tt><br/>
15661           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15662           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15663           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15664           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15665          </form>
15666        </doc:source>
15667        <doc:scenario>
15668          it('should initialize to model', function() {
15669            expect(binding('text')).toEqual('guest');
15670            expect(binding('myForm.input.$valid')).toEqual('true');
15671          });
15672
15673          it('should be invalid if empty', function() {
15674            input('text').enter('');
15675            expect(binding('text')).toEqual('');
15676            expect(binding('myForm.input.$valid')).toEqual('false');
15677          });
15678
15679          it('should be invalid if multi word', function() {
15680            input('text').enter('hello world');
15681            expect(binding('myForm.input.$valid')).toEqual('false');
15682          });
15683
15684          it('should not be trimmed', function() {
15685            input('text').enter('untrimmed ');
15686            expect(binding('text')).toEqual('untrimmed ');
15687            expect(binding('myForm.input.$valid')).toEqual('true');
15688          });
15689        </doc:scenario>
15690      </doc:example>
15691   */
15692  'text': textInputType,
15693
15694
15695  /**
15696   * @ngdoc inputType
15697   * @name ng.directive:input.number
15698   *
15699   * @description
15700   * Text input with number validation and transformation. Sets the `number` validation
15701   * error if not a valid number.
15702   *
15703   * @param {string} ngModel Assignable angular expression to data-bind to.
15704   * @param {string=} name Property name of the form under which the control is published.
15705   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
15706   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
15707   * @param {string=} required Sets `required` validation error key if the value is not entered.
15708   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15709   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15710   *    `required` when you want to data-bind to the `required` attribute.
15711   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15712   *    minlength.
15713   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15714   *    maxlength.
15715   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15716   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15717   *    patterns defined as scope expressions.
15718   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15719   *    interaction with the input element.
15720   *
15721   * @example
15722      <doc:example>
15723        <doc:source>
15724         <script>
15725           function Ctrl($scope) {
15726             $scope.value = 12;
15727           }
15728         </script>
15729         <form name="myForm" ng-controller="Ctrl">
15730           Number: <input type="number" name="input" ng-model="value"
15731                          min="0" max="99" required>
15732           <span class="error" ng-show="myForm.input.$error.required">
15733             Required!</span>
15734           <span class="error" ng-show="myForm.input.$error.number">
15735             Not valid number!</span>
15736           <tt>value = {{value}}</tt><br/>
15737           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15738           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15739           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15740           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15741          </form>
15742        </doc:source>
15743        <doc:scenario>
15744          it('should initialize to model', function() {
15745           expect(binding('value')).toEqual('12');
15746           expect(binding('myForm.input.$valid')).toEqual('true');
15747          });
15748
15749          it('should be invalid if empty', function() {
15750           input('value').enter('');
15751           expect(binding('value')).toEqual('');
15752           expect(binding('myForm.input.$valid')).toEqual('false');
15753          });
15754
15755          it('should be invalid if over max', function() {
15756           input('value').enter('123');
15757           expect(binding('value')).toEqual('');
15758           expect(binding('myForm.input.$valid')).toEqual('false');
15759          });
15760        </doc:scenario>
15761      </doc:example>
15762   */
15763  'number': numberInputType,
15764
15765
15766  /**
15767   * @ngdoc inputType
15768   * @name ng.directive:input.url
15769   *
15770   * @description
15771   * Text input with URL validation. Sets the `url` validation error key if the content is not a
15772   * valid URL.
15773   *
15774   * @param {string} ngModel Assignable angular expression to data-bind to.
15775   * @param {string=} name Property name of the form under which the control is published.
15776   * @param {string=} required Sets `required` validation error key if the value is not entered.
15777   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15778   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15779   *    `required` when you want to data-bind to the `required` attribute.
15780   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15781   *    minlength.
15782   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15783   *    maxlength.
15784   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15785   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15786   *    patterns defined as scope expressions.
15787   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15788   *    interaction with the input element.
15789   *
15790   * @example
15791      <doc:example>
15792        <doc:source>
15793         <script>
15794           function Ctrl($scope) {
15795             $scope.text = 'http://google.com';
15796           }
15797         </script>
15798         <form name="myForm" ng-controller="Ctrl">
15799           URL: <input type="url" name="input" ng-model="text" required>
15800           <span class="error" ng-show="myForm.input.$error.required">
15801             Required!</span>
15802           <span class="error" ng-show="myForm.input.$error.url">
15803             Not valid url!</span>
15804           <tt>text = {{text}}</tt><br/>
15805           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15806           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15807           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15808           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15809           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
15810          </form>
15811        </doc:source>
15812        <doc:scenario>
15813          it('should initialize to model', function() {
15814            expect(binding('text')).toEqual('http://google.com');
15815            expect(binding('myForm.input.$valid')).toEqual('true');
15816          });
15817
15818          it('should be invalid if empty', function() {
15819            input('text').enter('');
15820            expect(binding('text')).toEqual('');
15821            expect(binding('myForm.input.$valid')).toEqual('false');
15822          });
15823
15824          it('should be invalid if not url', function() {
15825            input('text').enter('xxx');
15826            expect(binding('myForm.input.$valid')).toEqual('false');
15827          });
15828        </doc:scenario>
15829      </doc:example>
15830   */
15831  'url': urlInputType,
15832
15833
15834  /**
15835   * @ngdoc inputType
15836   * @name ng.directive:input.email
15837   *
15838   * @description
15839   * Text input with email validation. Sets the `email` validation error key if not a valid email
15840   * address.
15841   *
15842   * @param {string} ngModel Assignable angular expression to data-bind to.
15843   * @param {string=} name Property name of the form under which the control is published.
15844   * @param {string=} required Sets `required` validation error key if the value is not entered.
15845   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15846   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15847   *    `required` when you want to data-bind to the `required` attribute.
15848   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15849   *    minlength.
15850   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15851   *    maxlength.
15852   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15853   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15854   *    patterns defined as scope expressions.
15855   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15856   *    interaction with the input element.
15857   *
15858   * @example
15859      <doc:example>
15860        <doc:source>
15861         <script>
15862           function Ctrl($scope) {
15863             $scope.text = '[email protected]';
15864           }
15865         </script>
15866           <form name="myForm" ng-controller="Ctrl">
15867             Email: <input type="email" name="input" ng-model="text" required>
15868             <span class="error" ng-show="myForm.input.$error.required">
15869               Required!</span>
15870             <span class="error" ng-show="myForm.input.$error.email">
15871               Not valid email!</span>
15872             <tt>text = {{text}}</tt><br/>
15873             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15874             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15875             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15876             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15877             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
15878           </form>
15879        </doc:source>
15880        <doc:scenario>
15881          it('should initialize to model', function() {
15882            expect(binding('text')).toEqual('[email protected]');
15883            expect(binding('myForm.input.$valid')).toEqual('true');
15884          });
15885
15886          it('should be invalid if empty', function() {
15887            input('text').enter('');
15888            expect(binding('text')).toEqual('');
15889            expect(binding('myForm.input.$valid')).toEqual('false');
15890          });
15891
15892          it('should be invalid if not email', function() {
15893            input('text').enter('xxx');
15894            expect(binding('myForm.input.$valid')).toEqual('false');
15895          });
15896        </doc:scenario>
15897      </doc:example>
15898   */
15899  'email': emailInputType,
15900
15901
15902  /**
15903   * @ngdoc inputType
15904   * @name ng.directive:input.radio
15905   *
15906   * @description
15907   * HTML radio button.
15908   *
15909   * @param {string} ngModel Assignable angular expression to data-bind to.
15910   * @param {string} value The value to which the expression should be set when selected.
15911   * @param {string=} name Property name of the form under which the control is published.
15912   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15913   *    interaction with the input element.
15914   * @param {string} ngValue Angular expression which sets the value to which the expression should
15915   *    be set when selected.
15916   *
15917   * @example
15918      <doc:example>
15919        <doc:source>
15920         <script>
15921           function Ctrl($scope) {
15922             $scope.color = 'blue';
15923             $scope.specialValue = {
15924               "id": "12345",
15925               "value": "green"
15926             };
15927           }
15928         </script>
15929         <form name="myForm" ng-controller="Ctrl">
15930           <input type="radio" ng-model="color" value="red">  Red <br/>
15931           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
15932           <input type="radio" ng-model="color" value="blue"> Blue <br/>
15933           <tt>color = {{color | json}}</tt><br/>
15934          </form>
15935          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
15936        </doc:source>
15937        <doc:scenario>
15938          it('should change state', function() {
15939            expect(binding('color')).toEqual('"blue"');
15940
15941            input('color').select('red');
15942            expect(binding('color')).toEqual('"red"');
15943          });
15944        </doc:scenario>
15945      </doc:example>
15946   */
15947  'radio': radioInputType,
15948
15949
15950  /**
15951   * @ngdoc inputType
15952   * @name ng.directive:input.checkbox
15953   *
15954   * @description
15955   * HTML checkbox.
15956   *
15957   * @param {string} ngModel Assignable angular expression to data-bind to.
15958   * @param {string=} name Property name of the form under which the control is published.
15959   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
15960   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
15961   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15962   *    interaction with the input element.
15963   *
15964   * @example
15965      <doc:example>
15966        <doc:source>
15967         <script>
15968           function Ctrl($scope) {
15969             $scope.value1 = true;
15970             $scope.value2 = 'YES'
15971           }
15972         </script>
15973         <form name="myForm" ng-controller="Ctrl">
15974           Value1: <input type="checkbox" ng-model="value1"> <br/>
15975           Value2: <input type="checkbox" ng-model="value2"
15976                          ng-true-value="YES" ng-false-value="NO"> <br/>
15977           <tt>value1 = {{value1}}</tt><br/>
15978           <tt>value2 = {{value2}}</tt><br/>
15979          </form>
15980        </doc:source>
15981        <doc:scenario>
15982          it('should change state', function() {
15983            expect(binding('value1')).toEqual('true');
15984            expect(binding('value2')).toEqual('YES');
15985
15986            input('value1').check();
15987            input('value2').check();
15988            expect(binding('value1')).toEqual('false');
15989            expect(binding('value2')).toEqual('NO');
15990          });
15991        </doc:scenario>
15992      </doc:example>
15993   */
15994  'checkbox': checkboxInputType,
15995
15996  'hidden': noop,
15997  'button': noop,
15998  'submit': noop,
15999  'reset': noop
16000};
16001
16002// A helper function to call $setValidity and return the value / undefined,
16003// a pattern that is repeated a lot in the input validation logic.
16004function validate(ctrl, validatorName, validity, value){
16005  ctrl.$setValidity(validatorName, validity);
16006  return validity ? value : undefined;
16007}
16008
16009function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16010  // In composition mode, users are still inputing intermediate text buffer,
16011  // hold the listener until composition is done.
16012  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16013  if (!$sniffer.android) {
16014    var composing = false;
16015
16016    element.on('compositionstart', function(data) {
16017      composing = true;
16018    });
16019
16020    element.on('compositionend', function() {
16021      composing = false;
16022    });
16023  }
16024
16025  var listener = function() {
16026    if (composing) return;
16027    var value = element.val();
16028
16029    // By default we will trim the value
16030    // If the attribute ng-trim exists we will avoid trimming
16031    // e.g. <input ng-model="foo" ng-trim="false">
16032    if (toBoolean(attr.ngTrim || 'T')) {
16033      value = trim(value);
16034    }
16035
16036    if (ctrl.$viewValue !== value) {
16037      if (scope.$$phase) {
16038        ctrl.$setViewValue(value);
16039      } else {
16040        scope.$apply(function() {
16041          ctrl.$setViewValue(value);
16042        });
16043      }
16044    }
16045  };
16046
16047  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
16048  // input event on backspace, delete or cut
16049  if ($sniffer.hasEvent('input')) {
16050    element.on('input', listener);
16051  } else {
16052    var timeout;
16053
16054    var deferListener = function() {
16055      if (!timeout) {
16056        timeout = $browser.defer(function() {
16057          listener();
16058          timeout = null;
16059        });
16060      }
16061    };
16062
16063    element.on('keydown', function(event) {
16064      var key = event.keyCode;
16065
16066      // ignore
16067      //    command            modifiers                   arrows
16068      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
16069
16070      deferListener();
16071    });
16072
16073    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
16074    if ($sniffer.hasEvent('paste')) {
16075      element.on('paste cut', deferListener);
16076    }
16077  }
16078
16079  // if user paste into input using mouse on older browser
16080  // or form autocomplete on newer browser, we need "change" event to catch it
16081  element.on('change', listener);
16082
16083  ctrl.$render = function() {
16084    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
16085  };
16086
16087  // pattern validator
16088  var pattern = attr.ngPattern,
16089      patternValidator,
16090      match;
16091
16092  if (pattern) {
16093    var validateRegex = function(regexp, value) {
16094      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
16095    };
16096    match = pattern.match(/^\/(.*)\/([gim]*)$/);
16097    if (match) {
16098      pattern = new RegExp(match[1], match[2]);
16099      patternValidator = function(value) {
16100        return validateRegex(pattern, value);
16101      };
16102    } else {
16103      patternValidator = function(value) {
16104        var patternObj = scope.$eval(pattern);
16105
16106        if (!patternObj || !patternObj.test) {
16107          throw minErr('ngPattern')('noregexp',
16108            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
16109            patternObj, startingTag(element));
16110        }
16111        return validateRegex(patternObj, value);
16112      };
16113    }
16114
16115    ctrl.$formatters.push(patternValidator);
16116    ctrl.$parsers.push(patternValidator);
16117  }
16118
16119  // min length validator
16120  if (attr.ngMinlength) {
16121    var minlength = int(attr.ngMinlength);
16122    var minLengthValidator = function(value) {
16123      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
16124    };
16125
16126    ctrl.$parsers.push(minLengthValidator);
16127    ctrl.$formatters.push(minLengthValidator);
16128  }
16129
16130  // max length validator
16131  if (attr.ngMaxlength) {
16132    var maxlength = int(attr.ngMaxlength);
16133    var maxLengthValidator = function(value) {
16134      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
16135    };
16136
16137    ctrl.$parsers.push(maxLengthValidator);
16138    ctrl.$formatters.push(maxLengthValidator);
16139  }
16140}
16141
16142function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16143  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16144
16145  ctrl.$parsers.push(function(value) {
16146    var empty = ctrl.$isEmpty(value);
16147    if (empty || NUMBER_REGEXP.test(value)) {
16148      ctrl.$setValidity('number', true);
16149      return value === '' ? null : (empty ? value : parseFloat(value));
16150    } else {
16151      ctrl.$setValidity('number', false);
16152      return undefined;
16153    }
16154  });
16155
16156  ctrl.$formatters.push(function(value) {
16157    return ctrl.$isEmpty(value) ? '' : '' + value;
16158  });
16159
16160  if (attr.min) {
16161    var minValidator = function(value) {
16162      var min = parseFloat(attr.min);
16163      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
16164    };
16165
16166    ctrl.$parsers.push(minValidator);
16167    ctrl.$formatters.push(minValidator);
16168  }
16169
16170  if (attr.max) {
16171    var maxValidator = function(value) {
16172      var max = parseFloat(attr.max);
16173      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
16174    };
16175
16176    ctrl.$parsers.push(maxValidator);
16177    ctrl.$formatters.push(maxValidator);
16178  }
16179
16180  ctrl.$formatters.push(function(value) {
16181    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
16182  });
16183}
16184
16185function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16186  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16187
16188  var urlValidator = function(value) {
16189    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
16190  };
16191
16192  ctrl.$formatters.push(urlValidator);
16193  ctrl.$parsers.push(urlValidator);
16194}
16195
16196function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16197  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16198
16199  var emailValidator = function(value) {
16200    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
16201  };
16202
16203  ctrl.$formatters.push(emailValidator);
16204  ctrl.$parsers.push(emailValidator);
16205}
16206
16207function radioInputType(scope, element, attr, ctrl) {
16208  // make the name unique, if not defined
16209  if (isUndefined(attr.name)) {
16210    element.attr('name', nextUid());
16211  }
16212
16213  element.on('click', function() {
16214    if (element[0].checked) {
16215      scope.$apply(function() {
16216        ctrl.$setViewValue(attr.value);
16217      });
16218    }
16219  });
16220
16221  ctrl.$render = function() {
16222    var value = attr.value;
16223    element[0].checked = (value == ctrl.$viewValue);
16224  };
16225
16226  attr.$observe('value', ctrl.$render);
16227}
16228
16229function checkboxInputType(scope, element, attr, ctrl) {
16230  var trueValue = attr.ngTrueValue,
16231      falseValue = attr.ngFalseValue;
16232
16233  if (!isString(trueValue)) trueValue = true;
16234  if (!isString(falseValue)) falseValue = false;
16235
16236  element.on('click', function() {
16237    scope.$apply(function() {
16238      ctrl.$setViewValue(element[0].checked);
16239    });
16240  });
16241
16242  ctrl.$render = function() {
16243    element[0].checked = ctrl.$viewValue;
16244  };
16245
16246  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
16247  ctrl.$isEmpty = function(value) {
16248    return value !== trueValue;
16249  };
16250
16251  ctrl.$formatters.push(function(value) {
16252    return value === trueValue;
16253  });
16254
16255  ctrl.$parsers.push(function(value) {
16256    return value ? trueValue : falseValue;
16257  });
16258}
16259
16260
16261/**
16262 * @ngdoc directive
16263 * @name ng.directive:textarea
16264 * @restrict E
16265 *
16266 * @description
16267 * HTML textarea element control with angular data-binding. The data-binding and validation
16268 * properties of this element are exactly the same as those of the
16269 * {@link ng.directive:input input element}.
16270 *
16271 * @param {string} ngModel Assignable angular expression to data-bind to.
16272 * @param {string=} name Property name of the form under which the control is published.
16273 * @param {string=} required Sets `required` validation error key if the value is not entered.
16274 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16275 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16276 *    `required` when you want to data-bind to the `required` attribute.
16277 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16278 *    minlength.
16279 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16280 *    maxlength.
16281 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16282 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16283 *    patterns defined as scope expressions.
16284 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16285 *    interaction with the input element.
16286 */
16287
16288
16289/**
16290 * @ngdoc directive
16291 * @name ng.directive:input
16292 * @restrict E
16293 *
16294 * @description
16295 * HTML input element control with angular data-binding. Input control follows HTML5 input types
16296 * and polyfills the HTML5 validation behavior for older browsers.
16297 *
16298 * @param {string} ngModel Assignable angular expression to data-bind to.
16299 * @param {string=} name Property name of the form under which the control is published.
16300 * @param {string=} required Sets `required` validation error key if the value is not entered.
16301 * @param {boolean=} ngRequired Sets `required` attribute if set to true
16302 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16303 *    minlength.
16304 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16305 *    maxlength.
16306 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16307 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16308 *    patterns defined as scope expressions.
16309 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16310 *    interaction with the input element.
16311 *
16312 * @example
16313    <doc:example>
16314      <doc:source>
16315       <script>
16316         function Ctrl($scope) {
16317           $scope.user = {name: 'guest', last: 'visitor'};
16318         }
16319       </script>
16320       <div ng-controller="Ctrl">
16321         <form name="myForm">
16322           User name: <input type="text" name="userName" ng-model="user.name" required>
16323           <span class="error" ng-show="myForm.userName.$error.required">
16324             Required!</span><br>
16325           Last name: <input type="text" name="lastName" ng-model="user.last"
16326             ng-minlength="3" ng-maxlength="10">
16327           <span class="error" ng-show="myForm.lastName.$error.minlength">
16328             Too short!</span>
16329           <span class="error" ng-show="myForm.lastName.$error.maxlength">
16330             Too long!</span><br>
16331         </form>
16332         <hr>
16333         <tt>user = {{user}}</tt><br/>
16334         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
16335         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
16336         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
16337         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
16338         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16339         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16340         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
16341         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
16342       </div>
16343      </doc:source>
16344      <doc:scenario>
16345        it('should initialize to model', function() {
16346          expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
16347          expect(binding('myForm.userName.$valid')).toEqual('true');
16348          expect(binding('myForm.$valid')).toEqual('true');
16349        });
16350
16351        it('should be invalid if empty when required', function() {
16352          input('user.name').enter('');
16353          expect(binding('user')).toEqual('{"last":"visitor"}');
16354          expect(binding('myForm.userName.$valid')).toEqual('false');
16355          expect(binding('myForm.$valid')).toEqual('false');
16356        });
16357
16358        it('should be valid if empty when min length is set', function() {
16359          input('user.last').enter('');
16360          expect(binding('user')).toEqual('{"name":"guest","last":""}');
16361          expect(binding('myForm.lastName.$valid')).toEqual('true');
16362          expect(binding('myForm.$valid')).toEqual('true');
16363        });
16364
16365        it('should be invalid if less than required min length', function() {
16366          input('user.last').enter('xx');
16367          expect(binding('user')).toEqual('{"name":"guest"}');
16368          expect(binding('myForm.lastName.$valid')).toEqual('false');
16369          expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
16370          expect(binding('myForm.$valid')).toEqual('false');
16371        });
16372
16373        it('should be invalid if longer than max length', function() {
16374          input('user.last').enter('some ridiculously long name');
16375          expect(binding('user'))
16376            .toEqual('{"name":"guest"}');
16377          expect(binding('myForm.lastName.$valid')).toEqual('false');
16378          expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
16379          expect(binding('myForm.$valid')).toEqual('false');
16380        });
16381      </doc:scenario>
16382    </doc:example>
16383 */
16384var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
16385  return {
16386    restrict: 'E',
16387    require: '?ngModel',
16388    link: function(scope, element, attr, ctrl) {
16389      if (ctrl) {
16390        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
16391                                                            $browser);
16392      }
16393    }
16394  };
16395}];
16396
16397var VALID_CLASS = 'ng-valid',
16398    INVALID_CLASS = 'ng-invalid',
16399    PRISTINE_CLASS = 'ng-pristine',
16400    DIRTY_CLASS = 'ng-dirty';
16401
16402/**
16403 * @ngdoc object
16404 * @name ng.directive:ngModel.NgModelController
16405 *
16406 * @property {string} $viewValue Actual string value in the view.
16407 * @property {*} $modelValue The value in the model, that the control is bound to.
16408 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
16409       the control reads value from the DOM.  Each function is called, in turn, passing the value
16410       through to the next. Used to sanitize / convert the value as well as validation.
16411       For validation, the parsers should update the validity state using
16412       {@link ng.directive:ngModel.NgModelController#methods_$setValidity $setValidity()},
16413       and return `undefined` for invalid values.
16414
16415 *
16416 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
16417       the model value changes. Each function is called, in turn, passing the value through to the
16418       next. Used to format / convert values for display in the control and validation.
16419 *      <pre>
16420 *      function formatter(value) {
16421 *        if (value) {
16422 *          return value.toUpperCase();
16423 *        }
16424 *      }
16425 *      ngModel.$formatters.push(formatter);
16426 *      </pre>
16427 *
16428 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
16429 *     view value has changed. It is called with no arguments, and its return value is ignored.
16430 *     This can be used in place of additional $watches against the model value.
16431 *
16432 * @property {Object} $error An object hash with all errors as keys.
16433 *
16434 * @property {boolean} $pristine True if user has not interacted with the control yet.
16435 * @property {boolean} $dirty True if user has already interacted with the control.
16436 * @property {boolean} $valid True if there is no error.
16437 * @property {boolean} $invalid True if at least one error on the control.
16438 *
16439 * @description
16440 *
16441 * `NgModelController` provides API for the `ng-model` directive. The controller contains
16442 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
16443 * purposefully does not contain any logic which deals with DOM rendering or listening to
16444 * DOM events. Such DOM related logic should be provided by other directives which make use of
16445 * `NgModelController` for data-binding.
16446 *
16447 * ## Custom Control Example
16448 * This example shows how to use `NgModelController` with a custom control to achieve
16449 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
16450 * collaborate together to achieve the desired result.
16451 *
16452 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
16453 * contents be edited in place by the user.  This will not work on older browsers.
16454 *
16455 * <example module="customControl">
16456    <file name="style.css">
16457      [contenteditable] {
16458        border: 1px solid black;
16459        background-color: white;
16460        min-height: 20px;
16461      }
16462
16463      .ng-invalid {
16464        border: 1px solid red;
16465      }
16466
16467    </file>
16468    <file name="script.js">
16469      angular.module('customControl', []).
16470        directive('contenteditable', function() {
16471          return {
16472            restrict: 'A', // only activate on element attribute
16473            require: '?ngModel', // get a hold of NgModelController
16474            link: function(scope, element, attrs, ngModel) {
16475              if(!ngModel) return; // do nothing if no ng-model
16476
16477              // Specify how UI should be updated
16478              ngModel.$render = function() {
16479                element.html(ngModel.$viewValue || '');
16480              };
16481
16482              // Listen for change events to enable binding
16483              element.on('blur keyup change', function() {
16484                scope.$apply(read);
16485              });
16486              read(); // initialize
16487
16488              // Write data to the model
16489              function read() {
16490                var html = element.html();
16491                // When we clear the content editable the browser leaves a <br> behind
16492                // If strip-br attribute is provided then we strip this out
16493                if( attrs.stripBr && html == '<br>' ) {
16494                  html = '';
16495                }
16496                ngModel.$setViewValue(html);
16497              }
16498            }
16499          };
16500        });
16501    </file>
16502    <file name="index.html">
16503      <form name="myForm">
16504       <div contenteditable
16505            name="myWidget" ng-model="userContent"
16506            strip-br="true"
16507            required>Change me!</div>
16508        <span ng-show="myForm.myWidget.$error.required">Required!</span>
16509       <hr>
16510       <textarea ng-model="userContent"></textarea>
16511      </form>
16512    </file>
16513    <file name="scenario.js">
16514      it('should data-bind and become invalid', function() {
16515        var contentEditable = element('[contenteditable]');
16516
16517        expect(contentEditable.text()).toEqual('Change me!');
16518        input('userContent').enter('');
16519        expect(contentEditable.text()).toEqual('');
16520        expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
16521      });
16522    </file>
16523 * </example>
16524 *
16525 *
16526 */
16527var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
16528    function($scope, $exceptionHandler, $attr, $element, $parse) {
16529  this.$viewValue = Number.NaN;
16530  this.$modelValue = Number.NaN;
16531  this.$parsers = [];
16532  this.$formatters = [];
16533  this.$viewChangeListeners = [];
16534  this.$pristine = true;
16535  this.$dirty = false;
16536  this.$valid = true;
16537  this.$invalid = false;
16538  this.$name = $attr.name;
16539
16540  var ngModelGet = $parse($attr.ngModel),
16541      ngModelSet = ngModelGet.assign;
16542
16543  if (!ngModelSet) {
16544    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
16545        $attr.ngModel, startingTag($element));
16546  }
16547
16548  /**
16549   * @ngdoc function
16550   * @name ng.directive:ngModel.NgModelController#$render
16551   * @methodOf ng.directive:ngModel.NgModelController
16552   *
16553   * @description
16554   * Called when the view needs to be updated. It is expected that the user of the ng-model
16555   * directive will implement this method.
16556   */
16557  this.$render = noop;
16558
16559  /**
16560   * @ngdoc function
16561   * @name { ng.directive:ngModel.NgModelController#$isEmpty
16562   * @methodOf ng.directive:ngModel.NgModelController
16563   *
16564   * @description
16565   * This is called when we need to determine if the value of the input is empty.
16566   *
16567   * For instance, the required directive does this to work out if the input has data or not.
16568   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
16569   *
16570   * You can override this for input directives whose concept of being empty is different to the
16571   * default. The `checkboxInputType` directive does this because in 
16571its case a value of `false`
16572   * implies empty.
16573   */
16574  this.$isEmpty = function(value) {
16575    return isUndefined(value) || value === '' || value === null || value !== value;
16576  };
16577
16578  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
16579      invalidCount = 0, // used to easily determine if we are valid
16580      $error = this.$error = {}; // keep invalid keys here
16581
16582
16583  // Setup initial state of the control
16584  $element.addClass(PRISTINE_CLASS);
16585  toggleValidCss(true);
16586
16587  // convenience method for easy toggling of classes
16588  function toggleValidCss(isValid, validationErrorKey) {
16589    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16590    $element.
16591      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
16592      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
16593  }
16594
16595  /**
16596   * @ngdoc function
16597   * @name ng.directive:ngModel.NgModelController#$setValidity
16598   * @methodOf ng.directive:ngModel.NgModelController
16599   *
16600   * @description
16601   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
16602   * does not notify form if given validator is already marked as invalid).
16603   *
16604   * This method should be called by validators - i.e. the parser or formatter functions.
16605   *
16606   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
16607   *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
16608   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
16609   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
16610   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
16611   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
16612   */
16613  this.$setValidity = function(validationErrorKey, isValid) {
16614    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
16615    // jshint -W018
16616    if ($error[validationErrorKey] === !isValid) return;
16617    // jshint +W018
16618
16619    if (isValid) {
16620      if ($error[validationErrorKey]) invalidCount--;
16621      if (!invalidCount) {
16622        toggleValidCss(true);
16623        this.$valid = true;
16624        this.$invalid = false;
16625      }
16626    } else {
16627      toggleValidCss(false);
16628      this.$invalid = true;
16629      this.$valid = false;
16630      invalidCount++;
16631    }
16632
16633    $error[validationErrorKey] = !isValid;
16634    toggleValidCss(isValid, validationErrorKey);
16635
16636    parentForm.$setValidity(validationErrorKey, isValid, this);
16637  };
16638
16639  /**
16640   * @ngdoc function
16641   * @name ng.directive:ngModel.NgModelController#$setPristine
16642   * @methodOf ng.directive:ngModel.NgModelController
16643   *
16644   * @description
16645   * Sets the control to its pristine state.
16646   *
16647   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
16648   * state (ng-pristine class).
16649   */
16650  this.$setPristine = function () {
16651    this.$dirty = false;
16652    this.$pristine = true;
16653    $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
16654  };
16655
16656  /**
16657   * @ngdoc function
16658   * @name ng.directive:ngModel.NgModelController#$setViewValue
16659   * @methodOf ng.directive:ngModel.NgModelController
16660   *
16661   * @description
16662   * Update the view value.
16663   *
16664   * This method should be called when the view value changes, typically from within a DOM event handler.
16665   * For example {@link ng.directive:input input} and
16666   * {@link ng.directive:select select} directives call it.
16667   *
16668   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
16669   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
16670   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
16671   *
16672   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
16673   *
16674   * Note that calling this function does not trigger a `$digest`.
16675   *
16676   * @param {string} value Value from the view.
16677   */
16678  this.$setViewValue = function(value) {
16679    this.$viewValue = value;
16680
16681    // change to dirty
16682    if (this.$pristine) {
16683      this.$dirty = true;
16684      this.$pristine = false;
16685      $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
16686      parentForm.$setDirty();
16687    }
16688
16689    forEach(this.$parsers, function(fn) {
16690      value = fn(value);
16691    });
16692
16693    if (this.$modelValue !== value) {
16694      this.$modelValue = value;
16695      ngModelSet($scope, value);
16696      forEach(this.$viewChangeListeners, function(listener) {
16697        try {
16698          listener();
16699        } catch(e) {
16700          $exceptionHandler(e);
16701        }
16702      });
16703    }
16704  };
16705
16706  // model -> value
16707  var ctrl = this;
16708
16709  $scope.$watch(function ngModelWatch() {
16710    var value = ngModelGet($scope);
16711
16712    // if scope model value and ngModel value are out of sync
16713    if (ctrl.$modelValue !== value) {
16714
16715      var formatters = ctrl.$formatters,
16716          idx = formatters.length;
16717
16718      ctrl.$modelValue = value;
16719      while(idx--) {
16720        value = formatters[idx](value);
16721      }
16722
16723      if (ctrl.$viewValue !== value) {
16724        ctrl.$viewValue = value;
16725        ctrl.$render();
16726      }
16727    }
16728
16729    return value;
16730  });
16731}];
16732
16733
16734/**
16735 * @ngdoc directive
16736 * @name ng.directive:ngModel
16737 *
16738 * @element input
16739 *
16740 * @description
16741 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
16742 * property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController},
16743 * which is created and exposed by this directive.
16744 *
16745 * `ngModel` is responsible for:
16746 *
16747 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
16748 *   require.
16749 * - Providing validation behavior (i.e. required, number, email, url).
16750 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
16751 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`).
16752 * - Registering the control with its parent {@link ng.directive:form form}.
16753 *
16754 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
16755 * current scope. If the property doesn't already exist on this scope, it will be created
16756 * implicitly and added to the scope.
16757 *
16758 * For best practices on using `ngModel`, see:
16759 *
16760 *  - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes}
16761 *
16762 * For basic examples, how to use `ngModel`, see:
16763 *
16764 *  - {@link ng.directive:input input}
16765 *    - {@link ng.directive:input.text text}
16766 *    - {@link ng.directive:input.checkbox checkbox}
16767 *    - {@link ng.directive:input.radio radio}
16768 *    - {@link ng.directive:input.number number}
16769 *    - {@link ng.directive:input.email email}
16770 *    - {@link ng.directive:input.url url}
16771 *  - {@link ng.directive:select select}
16772 *  - {@link ng.directive:textarea textarea}
16773 *
16774 */
16775var ngModelDirective = function() {
16776  return {
16777    require: ['ngModel', '^?form'],
16778    controller: NgModelController,
16779    link: function(scope, element, attr, ctrls) {
16780      // notify others, especially parent forms
16781
16782      var modelCtrl = ctrls[0],
16783          formCtrl = ctrls[1] || nullFormCtrl;
16784
16785      formCtrl.$addControl(modelCtrl);
16786
16787      scope.$on('$destroy', function() {
16788        formCtrl.$removeControl(modelCtrl);
16789      });
16790    }
16791  };
16792};
16793
16794
16795/**
16796 * @ngdoc directive
16797 * @name ng.directive:ngChange
16798 *
16799 * @description
16800 * Evaluate the given expression when the user changes the input.
16801 * The expression is evaluated immediately, unlike the JavaScript onchange event
16802 * which only triggers at the end of a change (usually, when the user leaves the
16803 * form element or presses the return key).
16804 * The expression is not evaluated when the value change is coming from the model.
16805 *
16806 * Note, this directive requires `ngModel` to be present.
16807 *
16808 * @element input
16809 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
16810 * in input value.
16811 *
16812 * @example
16813 * <doc:example>
16814 *   <doc:source>
16815 *     <script>
16816 *       function Controller($scope) {
16817 *         $scope.counter = 0;
16818 *         $scope.change = function() {
16819 *           $scope.counter++;
16820 *         };
16821 *       }
16822 *     </script>
16823 *     <div ng-controller="Controller">
16824 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
16825 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
16826 *       <label for="ng-change-example2">Confirmed</label><br />
16827 *       debug = {{confirmed}}<br />
16828 *       counter = {{counter}}
16829 *     </div>
16830 *   </doc:source>
16831 *   <doc:scenario>
16832 *     it('should evaluate the expression if changing from view', function() {
16833 *       expect(binding('counter')).toEqual('0');
16834 *       element('#ng-change-example1').click();
16835 *       expect(binding('counter')).toEqual('1');
16836 *       expect(binding('confirmed')).toEqual('true');
16837 *     });
16838 *
16839 *     it('should not evaluate the expression if changing from model', function() {
16840 *       element('#ng-change-example2').click();
16841 *       expect(binding('counter')).toEqual('0');
16842 *       expect(binding('confirmed')).toEqual('true');
16843 *     });
16844 *   </doc:scenario>
16845 * </doc:example>
16846 */
16847var ngChangeDirective = valueFn({
16848  require: 'ngModel',
16849  link: function(scope, element, attr, ctrl) {
16850    ctrl.$viewChangeListeners.push(function() {
16851      scope.$eval(attr.ngChange);
16852    });
16853  }
16854});
16855
16856
16857var requiredDirective = function() {
16858  return {
16859    require: '?ngModel',
16860    link: function(scope, elm, attr, ctrl) {
16861      if (!ctrl) return;
16862      attr.required = true; // force truthy in case we are on non input element
16863
16864      var validator = function(value) {
16865        if (attr.required && ctrl.$isEmpty(value)) {
16866          ctrl.$setValidity('required', false);
16867          return;
16868        } else {
16869          ctrl.$setValidity('required', true);
16870          return value;
16871        }
16872      };
16873
16874      ctrl.$formatters.push(validator);
16875      ctrl.$parsers.unshift(validator);
16876
16877      attr.$observe('required', function() {
16878        validator(ctrl.$viewValue);
16879      });
16880    }
16881  };
16882};
16883
16884
16885/**
16886 * @ngdoc directive
16887 * @name ng.directive:ngList
16888 *
16889 * @description
16890 * Text input that converts between a delimited string and an array of strings. The delimiter
16891 * can be a fixed string (by default a comma) or a regular expression.
16892 *
16893 * @element input
16894 * @param {string=} ngList optional delimiter that should be used to split the value. If
16895 *   specified in form `/something/` then the value will be converted into a regular expression.
16896 *
16897 * @example
16898    <doc:example>
16899      <doc:source>
16900       <script>
16901         function Ctrl($scope) {
16902           $scope.names = ['igor', 'misko', 'vojta'];
16903         }
16904       </script>
16905       <form name="myForm" ng-controller="Ctrl">
16906         List: <input name="namesInput" ng-model="names" ng-list required>
16907         <span class="error" ng-show="myForm.namesInput.$error.required">
16908           Required!</span>
16909         <br>
16910         <tt>names = {{names}}</tt><br/>
16911         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
16912         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
16913         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16914         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16915        </form>
16916      </doc:source>
16917      <doc:scenario>
16918        it('should initialize to model', function() {
16919          expect(binding('names')).toEqual('["igor","misko","vojta"]');
16920          expect(binding('myForm.namesInput.$valid')).toEqual('true');
16921          expect(element('span.error').css('display')).toBe('none');
16922        });
16923
16924        it('should be invalid if empty', function() {
16925          input('names').enter('');
16926          expect(binding('names')).toEqual('');
16927          expect(binding('myForm.namesInput.$valid')).toEqual('false');
16928          expect(element('span.error').css('display')).not().toBe('none');
16929        });
16930      </doc:scenario>
16931    </doc:example>
16932 */
16933var ngListDirective = function() {
16934  return {
16935    require: 'ngModel',
16936    link: function(scope, element, attr, ctrl) {
16937      var match = /\/(.*)\//.exec(attr.ngList),
16938          separator = match && new RegExp(match[1]) || attr.ngList || ',';
16939
16940      var parse = function(viewValue) {
16941        // If the viewValue is invalid (say required but empty) it will be `undefined`
16942        if (isUndefined(viewValue)) return;
16943
16944        var list = [];
16945
16946        if (viewValue) {
16947          forEach(viewValue.split(separator), function(value) {
16948            if (value) list.push(trim(value));
16949          });
16950        }
16951
16952        return list;
16953      };
16954
16955      ctrl.$parsers.push(parse);
16956      ctrl.$formatters.push(function(value) {
16957        if (isArray(value)) {
16958          return value.join(', ');
16959        }
16960
16961        return undefined;
16962      });
16963
16964      // Override the standard $isEmpty because an empty array means the input is empty.
16965      ctrl.$isEmpty = function(value) {
16966        return !value || !value.length;
16967      };
16968    }
16969  };
16970};
16971
16972
16973var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
16974/**
16975 * @ngdoc directive
16976 * @name ng.directive:ngValue
16977 *
16978 * @description
16979 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
16980 * that when the element is selected, the `ngModel` of that element is set to the
16981 * bound value.
16982 *
16983 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
16984 * shown below.
16985 *
16986 * @element input
16987 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
16988 *   of the `input` element
16989 *
16990 * @example
16991    <doc:example>
16992      <doc:source>
16993       <script>
16994          function Ctrl($scope) {
16995            $scope.names = ['pizza', 'unicorns', 'robots'];
16996            $scope.my = { favorite: 'unicorns' };
16997          }
16998       </script>
16999        <form ng-controller="Ctrl">
17000          <h2>Which is your favorite?</h2>
17001            <label ng-repeat="name in names" for="{{name}}">
17002              {{name}}
17003              <input type="radio"
17004                     ng-model="my.favorite"
17005                     ng-value="name"
17006                     id="{{name}}"
17007                     name="favorite">
17008            </label>
17009          <div>You chose {{my.favorite}}</div>
17010        </form>
17011      </doc:source>
17012      <doc:scenario>
17013        it('should initialize to model', function() {
17014          expect(binding('my.favorite')).toEqual('unicorns');
17015        });
17016        it('should bind the values to the inputs', function() {
17017          input('my.favorite').select('pizza');
17018          expect(binding('my.favorite')).toEqual('pizza');
17019        });
17020      </doc:scenario>
17021    </doc:example>
17022 */
17023var ngValueDirective = function() {
17024  return {
17025    priority: 100,
17026    compile: function(tpl, tplAttr) {
17027      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
17028        return function ngValueConstantLink(scope, elm, attr) {
17029          attr.$set('value', scope.$eval(attr.ngValue));
17030        };
17031      } else {
17032        return function ngValueLink(scope, elm, attr) {
17033          scope.$watch(attr.ngValue, function valueWatchAction(value) {
17034            attr.$set('value', value);
17035          });
17036        };
17037      }
17038    }
17039  };
17040};
17041
17042/**
17043 * @ngdoc directive
17044 * @name ng.directive:ngBind
17045 * @restrict AC
17046 *
17047 * @description
17048 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
17049 * with the value of a given expression, and to update the text content when the value of that
17050 * expression changes.
17051 *
17052 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
17053 * `{{ expression }}` which is similar but less verbose.
17054 *
17055 * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
17056 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
17057 * element attribute, it makes the bindings invisible to the user while the page is loading.
17058 *
17059 * An alternative solution to this problem would be using the
17060 * {@link ng.directive:ngCloak ngCloak} directive.
17061 *
17062 *
17063 * @element ANY
17064 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
17065 *
17066 * @example
17067 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
17068   <doc:example>
17069     <doc:source>
17070       <script>
17071         function Ctrl($scope) {
17072           $scope.name = 'Whirled';
17073         }
17074       </script>
17075       <div ng-controller="Ctrl">
17076         Enter name: <input type="text" ng-model="name"><br>
17077         Hello <span ng-bind="name"></span>!
17078       </div>
17079     </doc:source>
17080     <doc:scenario>
17081       it('should check ng-bind', function() {
17082         expect(using('.doc-example-live').binding('name')).toBe('Whirled');
17083         using('.doc-example-live').input('name').enter('world');
17084         expect(using('.doc-example-live').binding('name')).toBe('world');
17085       });
17086     </doc:scenario>
17087   </doc:example>
17088 */
17089var ngBindDirective = ngDirective(function(scope, element, attr) {
17090  element.addClass('ng-binding').data('$binding', attr.ngBind);
17091  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
17092    // We are purposefully using == here rather than === because we want to
17093    // catch when value is "null or undefined"
17094    // jshint -W041
17095    element.text(value == undefined ? '' : value);
17096  });
17097});
17098
17099
17100/**
17101 * @ngdoc directive
17102 * @name ng.directive:ngBindTemplate
17103 *
17104 * @description
17105 * The `ngBindTemplate` directive specifies that the element
17106 * text content should be replaced with the interpolation of the template
17107 * in the `ngBindTemplate` attribute.
17108 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
17109 * expressions. This directive is needed since some HTML elements
17110 * (such as TITLE and OPTION) cannot contain SPAN elements.
17111 *
17112 * @element ANY
17113 * @param {string} ngBindTemplate template of form
17114 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
17115 *
17116 * @example
17117 * Try it here: enter text in text box and watch the greeting change.
17118   <doc:example>
17119     <doc:source>
17120       <script>
17121         function Ctrl($scope) {
17122           $scope.salutation = 'Hello';
17123           $scope.name = 'World';
17124         }
17125       </script>
17126       <div ng-controller="Ctrl">
17127        Salutation: <input type="text" ng-model="salutation"><br>
17128        Name: <input type="text" ng-model="name"><br>
17129        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
17130       </div>
17131     </doc:source>
17132     <doc:scenario>
17133       it('should check ng-bind', function() {
17134         expect(using('.doc-example-live').binding('salutation')).
17135           toBe('Hello');
17136         expect(using('.doc-example-live').binding('name')).
17137           toBe('World');
17138         using('.doc-example-live').input('salutation').enter('Greetings');
17139         using('.doc-example-live').input('name').enter('user');
17140         expect(using('.doc-example-live').binding('salutation')).
17141           toBe('Greetings');
17142         expect(using('.doc-example-live').binding('name')).
17143           toBe('user');
17144       });
17145     </doc:scenario>
17146   </doc:example>
17147 */
17148var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
17149  return function(scope, element, attr) {
17150    // TODO: move this to scenario runner
17151    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
17152    element.addClass('ng-binding').data('$binding', interpolateFn);
17153    attr.$observe('ngBindTemplate', function(value) {
17154      element.text(value);
17155    });
17156  };
17157}];
17158
17159
17160/**
17161 * @ngdoc directive
17162 * @name ng.directive:ngBindHtml
17163 *
17164 * @description
17165 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
17166 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
17167 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
17168 * is available, for example, by including {@link ngSanitize}
17168 in your module's dependencies (not in
17169 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
17170 * an explicitly trusted value via {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}.  See the example
17171 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
17172 *
17173 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
17174 * will have an exception (instead of an exploit.)
17175 *
17176 * @element ANY
17177 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
17178 *
17179 * @example
17180   Try it here: enter text in text box and watch the greeting change.
17181 
17182   <example module="ngBindHtmlExample" deps="angular-sanitize.js">
17183     <file name="index.html">
17184       <div ng-controller="ngBindHtmlCtrl">
17185        <p ng-bind-html="myHTML"></p>
17186       </div>
17187     </file>
17188     
17189     <file name="script.js">
17190       angular.module('ngBindHtmlExample', ['ngSanitize'])
17191
17192       .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
17193         $scope.myHTML =
17194            'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
17195       }]);
17196     </file>
17197
17198     <file name="scenario.js">
17199       it('should check ng-bind-html', function() {
17200         expect(using('.doc-example-live').binding('myHTML')).
17201           toBe(
17202           'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
17203           );
17204       });
17205     </file>
17206   </example>
17207 */
17208var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
17209  return function(scope, element, attr) {
17210    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
17211
17212    var parsed = $parse(attr.ngBindHtml);
17213    function getStringValue() { return (parsed(scope) || '').toString(); }
17214
17215    scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
17216      element.html($sce.getTrustedHtml(parsed(scope)) || '');
17217    });
17218  };
17219}];
17220
17221function classDirective(name, selector) {
17222  name = 'ngClass' + name;
17223  return function() {
17224    return {
17225      restrict: 'AC',
17226      link: function(scope, element, attr) {
17227        var oldVal;
17228
17229        scope.$watch(attr[name], ngClassWatchAction, true);
17230
17231        attr.$observe('class', function(value) {
17232          ngClassWatchAction(scope.$eval(attr[name]));
17233        });
17234
17235
17236        if (name !== 'ngClass') {
17237          scope.$watch('$index', function($index, old$index) {
17238            // jshint bitwise: false
17239            var mod = $index & 1;
17240            if (mod !== old$index & 1) {
17241              var classes = flattenClasses(scope.$eval(attr[name]));
17242              mod === selector ?
17243                attr.$addClass(classes) :
17244                attr.$removeClass(classes);
17245            }
17246          });
17247        }
17248
17249
17250        function ngClassWatchAction(newVal) {
17251          if (selector === true || scope.$index % 2 === selector) {
17252            var newClasses = flattenClasses(newVal || '');
17253            if(!oldVal) {
17254              attr.$addClass(newClasses);
17255            } else if(!equals(newVal,oldVal)) {
17256              attr.$updateClass(newClasses, flattenClasses(oldVal));
17257            }
17258          }
17259          oldVal = copy(newVal);
17260        }
17261
17262
17263        function flattenClasses(classVal) {
17264          if(isArray(classVal)) {
17265            return classVal.join(' ');
17266          } else if (isObject(classVal)) {
17267            var classes = [], i = 0;
17268            forEach(classVal, function(v, k) {
17269              if (v) {
17270                classes.push(k);
17271              }
17272            });
17273            return classes.join(' ');
17274          }
17275
17276          return classVal;
17277        }
17278      }
17279    };
17280  };
17281}
17282
17283/**
17284 * @ngdoc directive
17285 * @name ng.directive:ngClass
17286 * @restrict AC
17287 *
17288 * @description
17289 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
17290 * an expression that represents all classes to be added.
17291 *
17292 * The directive won't add duplicate classes if a particular class was already set.
17293 *
17294 * When the expression changes, the previously added classes are removed and only then the
17295 * new classes are added.
17296 *
17297 * @animations
17298 * add - happens just before the class is applied to the element
17299 * remove - happens just before the class is removed from the element
17300 *
17301 * @element ANY
17302 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
17303 *   of the evaluation can be a string representing space delimited class
17304 *   names, an array, or a map of class names to boolean values. In the case of a map, the
17305 *   names of the properties whose values are truthy will be added as css classes to the
17306 *   element.
17307 *
17308 * @example Example that demonstrates basic bindings via ngClass directive.
17309   <example>
17310     <file name="index.html">
17311       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
17312       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
17313       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
17314       <input type="checkbox" ng-model="error"> error (apply "red" class)
17315       <hr>
17316       <p ng-class="style">Using String Syntax</p>
17317       <input type="text" ng-model="style" placeholder="Type: bold strike red">
17318       <hr>
17319       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
17320       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
17321       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
17322       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
17323     </file>
17324     <file name="style.css">
17325       .strike {
17326         text-decoration: line-through;
17327       }
17328       .bold {
17329           font-weight: bold;
17330       }
17331       .red {
17332           color: red;
17333       }
17334     </file>
17335     <file name="scenario.js">
17336       it('should let you toggle the class', function() {
17337
17338         expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
17339         expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
17340
17341         input('important').check();
17342         expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
17343
17344         input('error').check();
17345         expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
17346       });
17347
17348       it('should let you toggle string example', function() {
17349         expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
17350         input('style').enter('red');
17351         expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red');
17352       });
17353
17354       it('array example should have 3 classes', function() {
17355         expect(element('.doc-example-live p:last').prop('className')).toBe('');
17356         input('style1').enter('bold');
17357         input('style2').enter('strike');
17358         input('style3').enter('red');
17359         expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red');
17360       });
17361     </file>
17362   </example>
17363
17364   ## Animations
17365
17366   The example below demonstrates how to perform animations using ngClass.
17367
17368   <example animations="true">
17369     <file name="index.html">
17370      <input type="button" value="set" ng-click="myVar='my-class'">
17371      <input type="button" value="clear" ng-click="myVar=''">
17372      <br>
17373      <span class="base-class" ng-class="myVar">Sample Text</span>
17374     </file>
17375     <file name="style.css">
17376       .base-class {
17377         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17378         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17379       }
17380
17381       .base-class.my-class {
17382         color: red;
17383         font-size:3em;
17384       }
17385     </file>
17386     <file name="scenario.js">
17387       it('should check ng-class', function() {
17388         expect(element('.doc-example-live span').prop('className')).not().
17389           toMatch(/my-class/);
17390
17391         using('.doc-example-live').element(':button:first').click();
17392
17393         expect(element('.doc-example-live span').prop('className')).
17394           toMatch(/my-class/);
17395
17396         using('.doc-example-live').element(':button:last').click();
17397
17398         expect(element('.doc-example-live span').prop('className')).not().
17399           toMatch(/my-class/);
17400       });
17401     </file>
17402   </example>
17403
17404
17405   ## ngClass and pre-existing CSS3 Transitions/Animations
17406   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
17407   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
17408   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
17409   to view the step by step details of {@link ngAnimate.$animate#methods_addclass $animate.addClass} and
17410   {@link ngAnimate.$animate#methods_removeclass $animate.removeClass}.
17411 */
17412var ngClassDirective = classDirective('', true);
17413
17414/**
17415 * @ngdoc directive
17416 * @name ng.directive:ngClassOdd
17417 * @restrict AC
17418 *
17419 * @description
17420 * The `ngClassOdd` and `ngClassEven` directives work exactly as
17421 * {@link ng.directive:ngClass ngClass}, except they work in
17422 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
17423 *
17424 * This directive can be applied only within the scope of an
17425 * {@link ng.directive:ngRepeat ngRepeat}.
17426 *
17427 * @element ANY
17428 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
17429 *   of the evaluation can be a string representing space delimited class names or an array.
17430 *
17431 * @example
17432   <example>
17433     <file name="index.html">
17434        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
17435          <li ng-repeat="name in names">
17436           <span ng-class-odd="'odd'" ng-class-even="'even'">
17437             {{name}}
17438           </span>
17439          </li>
17440        </ol>
17441     </file>
17442     <file name="style.css">
17443       .odd {
17444         color: red;
17445       }
17446       .even {
17447         color: blue;
17448       }
17449     </file>
17450     <file name="scenario.js">
17451       it('should check ng-class-odd and ng-class-even', function() {
17452         expect(element('.doc-example-live li:first span').prop('className')).
17453           toMatch(/odd/);
17454         expect(element('.doc-example-live li:last span').prop('className')).
17455           toMatch(/even/);
17456       });
17457     </file>
17458   </example>
17459 */
17460var ngClassOddDirective = classDirective('Odd', 0);
17461
17462/**
17463 * @ngdoc directive
17464 * @name ng.directive:ngClassEven
17465 * @restrict AC
17466 *
17467 * @description
17468 * The `ngClassOdd` and `ngClassEven` directives work exactly as
17469 * {@link ng.directive:ngClass ngClass}, except they work in
17470 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
17471 *
17472 * This directive can be applied only within the scope of an
17473 * {@link ng.directive:ngRepeat ngRepeat}.
17474 *
17475 * @element ANY
17476 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
17477 *   result of the evaluation can be a string representing space delimited class names or an array.
17478 *
17479 * @example
17480   <example>
17481     <file name="index.html">
17482        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
17483          <li ng-repeat="name in names">
17484           <span ng-class-odd="'odd'" ng-class-even="'even'">
17485             {{name}} &nbsp; &nbsp; &nbsp;
17486           </span>
17487          </li>
17488        </ol>
17489     </file>
17490     <file name="style.css">
17491       .odd {
17492         color: red;
17493       }
17494       .even {
17495         color: blue;
17496       }
17497     </file>
17498     <file name="scenario.js">
17499       it('should check ng-class-odd and ng-class-even', function() {
17500         expect(element('.doc-example-live li:first span').prop('className')).
17501           toMatch(/odd/);
17502         expect(element('.doc-example-live li:last span').prop('className')).
17503           toMatch(/even/);
17504       });
17505     </file>
17506   </example>
17507 */
17508var ngClassEvenDirective = classDirective('Even', 1);
17509
17510/**
17511 * @ngdoc directive
17512 * @name ng.directive:ngCloak
17513 * @restrict AC
17514 *
17515 * @description
17516 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
17517 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
17518 * directive to avoid the undesirable flicker effect caused by the html template display.
17519 *
17520 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
17521 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
17522 * of the browser view.
17523 *
17524 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
17525 * `angular.min.js`.
17526 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
17527 *
17528 * <pre>
17529 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
17530 *   display: none !important;
17531 * }
17532 * </pre>
17533 *
17534 * When this css rule is loaded by the browser, all html elements (including their children) that
17535 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
17536 * during the compilation of the template it deletes the `ngCloak` element attribute, making
17537 * the compiled element visible.
17538 *
17539 * For the best result, the `angular.js` script must be loaded in the head section of the html
17540 * document; alternatively, the css rule above must be included in the external stylesheet of the
17541 * application.
17542 *
17543 * Legacy browsers, like IE7, do not provide attribute selector support (a
17543dded in CSS 2.1) so they
17544 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
17545 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
17546 *
17547 * @element ANY
17548 *
17549 * @example
17550   <doc:example>
17551     <doc:source>
17552        <div id="template1" ng-cloak>{{ 'hello' }}</div>
17553        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
17554     </doc:source>
17555     <doc:scenario>
17556       it('should remove the template directive and css class', function() {
17557         expect(element('.doc-example-live #template1').attr('ng-cloak')).
17558           not().toBeDefined();
17559         expect(element('.doc-example-live #template2').attr('ng-cloak')).
17560           not().toBeDefined();
17561       });
17562     </doc:scenario>
17563   </doc:example>
17564 *
17565 */
17566var ngCloakDirective = ngDirective({
17567  compile: function(element, attr) {
17568    attr.$set('ngCloak', undefined);
17569    element.removeClass('ng-cloak');
17570  }
17571});
17572
17573/**
17574 * @ngdoc directive
17575 * @name ng.directive:ngController
17576 *
17577 * @description
17578 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
17579 * supports the principles behind the Model-View-Controller design pattern.
17580 *
17581 * MVC components in angular:
17582 *
17583 * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
17584 *   are accessed through bindings.
17585 * * View — The template (HTML with data bindings) that is rendered into the View.
17586 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
17587 *   logic behind the application to decorate the scope with functions and values
17588 *
17589 * Note that you can also attach controllers to the DOM by declaring it in a route definition
17590 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
17591 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
17592 * and executed twice.
17593 *
17594 * @element ANY
17595 * @scope
17596 * @param {expression} ngController Name of a globally accessible constructor function or an
17597 *     {@link guide/expression expression} that on the current scope evaluates to a
17598 *     constructor function. The controller instance can be published into a scope property
17599 *     by specifying `as propertyName`.
17600 *
17601 * @example
17602 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
17603 * greeting are methods declared on the controller (see source tab). These methods can
17604 * easily be called from the angular markup. Notice that the scope becomes the `this` for the
17605 * controller's instance. This allows for easy access to the view data from the controller. Also
17606 * notice that any changes to the data are automatically reflected in the View without the need
17607 * for a manual update. The example is shown in two different declaration styles you may use
17608 * according to preference.
17609   <doc:example>
17610     <doc:source>
17611      <script>
17612        function SettingsController1() {
17613          this.name = "John Smith";
17614          this.contacts = [
17615            {type: 'phone', value: '408 555 1212'},
17616            {type: 'email', value: '[email protected]'} ];
17617          };
17618
17619        SettingsController1.prototype.greet = function() {
17620          alert(this.name);
17621        };
17622
17623        SettingsController1.prototype.addContact = function() {
17624          this.contacts.push({type: 'email', value: '[email protected]'});
17625        };
17626
17627        SettingsController1.prototype.removeContact = function(contactToRemove) {
17628         var index = this.contacts.indexOf(contactToRemove);
17629          this.contacts.splice(index, 1);
17630        };
17631
17632        SettingsController1.prototype.clearContact = function(contact) {
17633          contact.type = 'phone';
17634          contact.value = '';
17635        };
17636      </script>
17637      <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
17638        Name: <input type="text" ng-model="settings.name"/>
17639        [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
17640        Contact:
17641        <ul>
17642          <li ng-repeat="contact in settings.contacts">
17643            <select ng-model="contact.type">
17644               <option>phone</option>
17645               <option>email</option>
17646            </select>
17647            <input type="text" ng-model="contact.value"/>
17648            [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
17649            | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
17650          </li>
17651          <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
17652       </ul>
17653      </div>
17654     </doc:source>
17655     <doc:scenario>
17656       it('should check controller as', function() {
17657         expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
17658         expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
17659           .toBe('408 555 1212');
17660         expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
17661           .toBe('[email protected]');
17662
17663         element('#ctrl-as-exmpl li:first a:contains("clear")').click();
17664         expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');
17665
17666         element('#ctrl-as-exmpl li:last a:contains("add")').click();
17667         expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
17668           .toBe('[email protected]');
17669       });
17670     </doc:scenario>
17671   </doc:example>
17672    <doc:example>
17673     <doc:source>
17674      <script>
17675        function SettingsController2($scope) {
17676          $scope.name = "John Smith";
17677          $scope.contacts = [
17678            {type:'phone', value:'408 555 1212'},
17679            {type:'email', value:'[email protected]'} ];
17680
17681          $scope.greet = function() {
17682           alert(this.name);
17683          };
17684
17685          $scope.addContact = function() {
17686           this.contacts.push({type:'email', value:'[email protected]'});
17687          };
17688
17689          $scope.removeContact = function(contactToRemove) {
17690           var index = this.contacts.indexOf(contactToRemove);
17691           this.contacts.splice(index, 1);
17692          };
17693
17694          $scope.clearContact = function(contact) {
17695           contact.type = 'phone';
17696           contact.value = '';
17697          };
17698        }
17699      </script>
17700      <div id="ctrl-exmpl" ng-controller="SettingsController2">
17701        Name: <input type="text" ng-model="name"/>
17702        [ <a href="" ng-click="greet()">greet</a> ]<br/>
17703        Contact:
17704        <ul>
17705          <li ng-repeat="contact in contacts">
17706            <select ng-model="contact.type">
17707               <option>phone</option>
17708               <option>email</option>
17709            </select>
17710            <input type="text" ng-model="contact.value"/>
17711            [ <a href="" ng-click="clearContact(contact)">clear</a>
17712            | <a href="" ng-click="removeContact(contact)">X</a> ]
17713          </li>
17714          <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
17715       </ul>
17716      </div>
17717     </doc:source>
17718     <doc:scenario>
17719       it('should check controller', function() {
17720         expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
17721         expect(element('#ctrl-exmpl li:nth-child(1) input').val())
17722           .toBe('408 555 1212');
17723         expect(element('#ctrl-exmpl li:nth-child(2) input').val())
17724           .toBe('[email protected]');
17725
17726         element('#ctrl-exmpl li:first a:contains("clear")').click();
17727         expect(element('#ctrl-exmpl li:first input').val()).toBe('');
17728
17729         element('#ctrl-exmpl li:last a:contains("add")').click();
17730         expect(element('#ctrl-exmpl li:nth-child(3) input').val())
17731           .toBe('[email protected]');
17732       });
17733     </doc:scenario>
17734   </doc:example>
17735
17736 */
17737var ngControllerDirective = [function() {
17738  return {
17739    scope: true,
17740    controller: '@',
17741    priority: 500
17742  };
17743}];
17744
17745/**
17746 * @ngdoc directive
17747 * @name ng.directive:ngCsp
17748 *
17749 * @element html
17750 * @description
17751 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
17752 *
17753 * This is necessary when developing things like Google Chrome Extensions.
17754 *
17755 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
17756 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
17757 * any of these restrictions.
17758 *
17759 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
17760 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
17761 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
17762 * be raised.
17763 *
17764 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
17765 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
17766 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
17767 *
17768 * In order to use this feature put the `ngCsp` directive on the root element of the application.
17769 *
17770 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
17771 *
17772 * @example
17773 * This example shows how to apply the `ngCsp` directive to the `html` tag.
17774   <pre>
17775     <!doctype html>
17776     <html ng-app ng-csp>
17777     ...
17778     ...
17779     </html>
17780   </pre>
17781 */
17782
17783// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
17784// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
17785// anywhere in the current doc
17786
17787/**
17788 * @ngdoc directive
17789 * @name ng.directive:ngClick
17790 *
17791 * @description
17792 * The ngClick directive allows you to specify custom behavior when
17793 * an element is clicked.
17794 *
17795 * @element ANY
17796 * @priority 0
17797 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
17798 * click. (Event object is available as `$event`)
17799 *
17800 * @example
17801   <doc:example>
17802     <doc:source>
17803      <button ng-click="count = count + 1" ng-init="count=0">
17804        Increment
17805      </button>
17806      count: {{count}}
17807     </doc:source>
17808     <doc:protractor>
17809       it('should check ng-click', function() {
17810         expect(element(by.binding('count')).getText()).toMatch('0');
17811         element(by.css('.doc-example-live button')).click();
17812         expect(element(by.binding('count')).getText()).toMatch('1');
17813       });
17814     </doc:protractor>
17815   </doc:example>
17816 */
17817/*
17818 * A directive that allows creation of custom onclick handlers that are defined as angular
17819 * expressions and are compiled and executed within the current scope.
17820 *
17821 * Events that are handled via these handler are always configured not to propagate further.
17822 */
17823var ngEventDirectives = {};
17824forEach(
17825  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
17826  function(name) {
17827    var directiveName = directiveNormalize('ng-' + name);
17828    ngEventDirectives[directiveName] = ['$parse', function($parse) {
17829      return {
17830        compile: function($element, attr) {
17831          var fn = $parse(attr[directiveName]);
17832          return function(scope, element, attr) {
17833            element.on(lowercase(name), function(event) {
17834              scope.$apply(function() {
17835                fn(scope, {$event:event});
17836              });
17837            });
17838          };
17839        }
17840      };
17841    }];
17842  }
17843);
17844
17845/**
17846 * @ngdoc directive
17847 * @name ng.directive:ngDblclick
17848 *
17849 * @description
17850 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
17851 *
17852 * @element ANY
17853 * @priority 0
17854 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
17855 * a dblclick. (The Event object is available as `$event`)
17856 *
17857 * @example
17858   <doc:example>
17859     <doc:source>
17860      <button ng-dblclick="count = count + 1" ng-init="count=0">
17861        Increment (on double click)
17862      </button>
17863      count: {{count}}
17864     </doc:source>
17865   </doc:example>
17866 */
17867
17868
17869/**
17870 * @ngdoc directive
17871 * @name ng.directive:ngMousedown
17872 *
17873 * @description
17874 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
17875 *
17876 * @element ANY
17877 * @priority 0
17878 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
17879 * mousedown. (Event object is available as `$event`)
17880 *
17881 * @example
17882   <doc:example>
17883     <doc:source>
17884      <button ng-mousedown="count = count + 1" ng-init="count=0">
17885        Increment (on mouse down)
17886      </button>
17887      count: {{count}}
17888     </doc:source>
17889   </doc:example>
17890 */
17891
17892
17893/**
17894 * @ngdoc directive
17895 * @name ng.directive:ngMouseup
17896 *
17897 * @description
17898 * Specify custom behavior on mouseup event.
17899 *
17900 * @element ANY
17901 * @priority 0
17902 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
17903 * mouseup. (Event object is available as `$event`)
17904 *
17905 * @example
17906   <doc:example>
17907     <doc:source>
17908      <button ng-mouseup="count = count + 1" ng-init="count=0">
17909        Increment (on mouse up)
17910      </button>
17911      count: {{count}}
17912     </doc:source>
17913   </doc:example>
17914 */
17915
17916/**
17917 * @ngdoc directive
17918 * @name ng.directive:ngMouseover
17919 *
17920 * @description
17921 * Specify custom behavior on mouseover event.
17922 *
17923 * @element ANY
17924 * @priority 0
17925 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
17926 * mouseover. (Event object is available as `$event`)
17927 *
17928 * @example
17929   <doc:example>
17930     <doc:source>
17931      <button ng-mouseover="count = count + 1" ng-init="count=0">
17932        Increment (when mouse is over)
17933      </button>
17934      count: {{count}}
17935     </doc:source>
17936   </doc:example>
17937 */
17938
17939
17940/**
17941 * @ngdoc directive
17942 * @name ng.directive:ngMouseenter
17943 *
17944 * @description
17945 * Specify custom behavior on mouseenter event.
17946 *
17947 * @element ANY
17948 * @priority 0
17949 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
17950 * mouseenter. (Event object is available as `$event`)
17951 *
17952 * @example
17953   <doc:example>
17954     <doc:source>
17955      <button ng-mouseenter="count = count + 1" ng-init="count=0">
17956        Increment (when mouse enters)
17957      </button>
17958      count: {{count}}
17959     </doc:source>
17960   </doc:example>
17961 */
17962
17963
17964/**
17965 * @ngdoc directive
17966 * @name ng.directive:ngMouseleave
17967 *
17968 * @description
17969 * Specify custom behavior on mouseleave event.
17970 *
17971 * @element ANY
17972 * @priority 0
17973 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
17974 * mouseleave. (Event object is available as `$event`)
17975 *
17976 * @example
17977   <doc:example>
17978     <doc:source>
17979      <button ng-mouseleave="count = count + 1" ng-init="count=0">
17980        Increment (when mouse leaves)
17981      </button>
17982      count: {{count}}
17983     </doc:source>
17984   </doc:example>
17985 */
17986
17987
17988/**
17989 * @ngdoc directive
17990 * @name ng.directive:ngMousemove
17991 *
17992 * @description
17993 * Specify custom behavior on mousemove event.
17994 *
17995 * @element ANY
17996 * @priority 0
17997 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
17998 * mousemove. (Event object is available as `$event`)
17999 *
18000 * @example
18001   <doc:example>
18002     <doc:source>
18003      <button ng-mousemove="count = count + 1" ng-init="count=0">
18004        Increment (when mouse moves)
18005      </button>
18006      count: {{count}}
18007     </doc:source>
18008   </doc:example>
18009 */
18010
18011
18012/**
18013 * @ngdoc directive
18014 * @name ng.directive:ngKeydown
18015 *
18016 * @description
18017 * Specify custom behavior on keydown event.
18018 *
18019 * @element ANY
18020 * @priority 0
18021 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
18022 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18023 *
18024 * @example
18025   <doc:example>
18026     <doc:source>
18027      <input ng-keydown="count = count + 1" ng-init="count=0">
18028      key down count: {{count}}
18029     </doc:source>
18030   </doc:example>
18031 */
18032
18033
18034/**
18035 * @ngdoc directive
18036 * @name ng.directive:ngKeyup
18037 *
18038 * @description
18039 * Specify custom behavior on keyup event.
18040 *
18041 * @element ANY
18042 * @priority 0
18043 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
18044 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18045 *
18046 * @example
18047   <doc:example>
18048     <doc:source>
18049      <input ng-keyup="count = count + 1" ng-init="count=0">
18050      key up count: {{count}}
18051     </doc:source>
18052   </doc:example>
18053 */
18054
18055
18056/**
18057 * @ngdoc directive
18058 * @name ng.directive:ngKeypress
18059 *
18060 * @description
18061 * Specify custom behavior on keypress event.
18062 *
18063 * @element ANY
18064 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
18065 * keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18066 *
18067 * @example
18068   <doc:example>
18069     <doc:source>
18070      <input ng-keypress="count = count + 1" ng-init="count=0">
18071      key press count: {{count}}
18072     </doc:source>
18073   </doc:example>
18074 */
18075
18076
18077/**
18078 * @ngdoc directive
18079 * @name ng.directive:ngSubmit
18080 *
18081 * @description
18082 * Enables binding angular expressions to onsubmit events.
18083 *
18084 * Additionally it prevents the default action (which for form means sending the request to the
18085 * server and reloading the current page) **but only if the form does not contain an `action`
18086 * attribute**.
18087 *
18088 * @element form
18089 * @priority 0
18090 * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
18091 *
18092 * @example
18093   <doc:example>
18094     <doc:source>
18095      <script>
18096        function Ctrl($scope) {
18097          $scope.list = [];
18098          $scope.text = 'hello';
18099          $scope.submit = function() {
18100            if (this.text) {
18101              this.list.push(this.text);
18102              this.text = '';
18103            }
18104          };
18105        }
18106      </script>
18107      <form ng-submit="submit()" ng-controller="Ctrl">
18108        Enter text and hit enter:
18109        <input type="text" ng-model="text" name="text" />
18110        <input type="submit" id="submit" value="Submit" />
18111        <pre>list={{list}}</pre>
18112      </form>
18113     </doc:source>
18114     <doc:scenario>
18115       it('should check ng-submit', function() {
18116         expect(binding('list')).toBe('[]');
18117         element('.doc-example-live #submit').click();
18118         expect(binding('list')).toBe('["hello"]');
18119         expect(input('text').val()).toBe('');
18120       });
18121       it('should ignore empty strings', function() {
18122         expect(binding('list')).toBe('[]');
18123         element('.doc-example-live #submit').click();
18124         element('.doc-example-live #submit').click();
18125         expect(binding('list')).toBe('["hello"]');
18126       });
18127     </doc:scenario>
18128   </doc:example>
18129 */
18130
18131/**
18132 * @ngdoc directive
18133 * @name ng.directive:ngFocus
18134 *
18135 * @description
18136 * Specify custom behavior on focus event.
18137 *
18138 * @element window, input, select, textarea, a
18139 * @priority 0
18140 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
18141 * focus. (Event object is available as `$event`)
18142 *
18143 * @example
18144 * See {@link ng.directive:ngClick ngClick}
18145 */
18146
18147/**
18148 * @ngdoc directive
18149 * @name ng.directive:ngBlur
18150 *
18151 * @description
18152 * Specify custom behavior on blur event.
18153 *
18154 * @element window, input, select, textarea, a
18155 * @priority 0
18156 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
18157 * blur. (Event object is available as `$event`)
18158 *
18159 * @example
18160 * See {@link ng.directive:ngClick ngClick}
18161 */
18162
18163/**
18164 * @ngdoc directive
18165 * @name ng.directive:ngCopy
18166 *
18167 * @description
18168 * Specify custom behavior on copy event.
18169 *
18170 * @element window, input, select, textarea, a
18171 * @priority 0
18172 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
18173 * copy. (Event object is available as `$event`)
18174 *
18175 * @example
18176   <doc:example>
18177     <doc:source>
18178      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
18179      copied: {{copied}}
18180     </doc:source>
18181   </doc:example>
18182 */
18183
18184/**
18185 * @ngdoc directive
18186 * @name ng.directive:ngCut
18187 *
18188 * @description
18189 * Specify custom behavior on cut event.
18190 *
18191 * @element window, input, select, textarea, a
18192 * @priority 0
18193 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
18194 * cut. (Event object is available as `$event`)
18195 *
18196 * @example
18197   <doc:example>
18198     <doc:source>
18199      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
18200      cut: {{cut}}
18201     </doc:source>
18202   </doc:example>
18203 */
18204
18205/**
18206 * @ngdoc directive
18207 * @name ng.directive:ngPaste
18208 *
18209 * @description
18210 * Specify custom behavior on paste event.
18211 *
18212 * @element window, input, select, textarea, a
18213 * @priority 0
18214 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
18215 * paste. (Event object is available as `$event`)
18216 *
18217 * @example
18218   <doc:example>
18219     <doc:source>
18220      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
18221      pasted: {{paste}}
18222     </doc:source>
18223   </doc:example>
18224 */
18225
18226/**
18227 * @ngdoc directive
18228 * @name ng.directive:ngIf
18229 * @restrict A
18230 *
18231 * @description
18232 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
18233 * {expression}. If the expression assigned to `ngIf` evaluates to a false
18234 * value then the element is removed from the DOM, otherwise a clone of the
18235 * element is reinserted into the DOM.
18236 *
18237 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
18238 * element in the DOM rather than changing its visibility via the `display` css property.  A common
18239 * case when this difference is significant is when using css selectors that rely on an element's
18240 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
18241 *
18242 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
18243 * is created when the element is restored.  The scope created within `ngIf` inherits from
18244 * its parent scope using
18245 * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
18246 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
18247 * a javascript primitive defined in the parent scope. In this case any modifications made to the
18248 * variable within the child scope will override (hide) the value in the parent scope.
18249 *
18250 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
18251 * is if an element's class attribute is directly modified after it's compiled, using something like
18252 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
18253 * the added class will be lost because the original compiled state is used to regenerate the element.
18254 *
18255 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
18256 * and `leave` effects.
18257 *
18258 * @animations
18259 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
18260 * leave - happens just before the ngIf contents are removed from the DOM
18261 *
18262 * @element ANY
18263 * @scope
18264 * @priority 600
18265 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
18266 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
18267 *     element is added to the DOM tree.
18268 *
18269 * @example
18270  <example animations="true">
18271    <file name="index.html">
18272      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
18273      Show when checked:
18274      <span ng-if="checked" class="animate-if">
18275        I'm removed when the checkbox is unchecked.
18276      </span>
18277    </file>
18278    <file name="animations.css">
18279      .animate-if {
18280        background:white;
18281        border:1px solid black;
18282        padding:10px;
18283      }
18284
18285      .animate-if.ng-enter, .animate-if.ng-leave {
18286        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18287        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18288      }
18289
18290      .animate-if.ng-enter,
18291      .animate-if.ng-leave.ng-leave-active {
18292        opacity:0;
18293      }
18294
18295      .animate-if.ng-leave,
18296      .animate-if.ng-enter.ng-enter-active {
18297        opacity:1;
18298      }
18299    </file>
18300  </example>
18301 */
18302var ngIfDirective = ['$animate', function($animate) {
18303  return {
18304    transclude: 'element',
18305    priority: 600,
18306    terminal: true,
18307    restrict: 'A',
18308    $$tlb: true,
18309    link: function ($scope, $element, $attr, ctrl, $transclude) {
18310        var block, childScope;
18311        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
18312
18313          if (toBoolean(value)) {
18314            if (!childScope) {
18315              childScope = $scope.$new();
18316              $transclude(childScope, function (clone) {
18317                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
18318                // Note: We only need the first/last node of the cloned nodes.
18319                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
18320                // by a directive with templateUrl when it's template arrives.
18321                block = {
18322                  clone: clone
18323                };
18324                $animate.enter(clone, $element.parent(), $element);
18325              });
18326            }
18327          } else {
18328
18329            if (childScope) {
18330              childScope.$destroy();
18331              childScope = null;
18332            }
18333
18334            if (block) {
18335              $animate.leave(getBlockElements(block.clone));
18336              block = null;
18337            }
18338          }
18339        });
18340    }
18341  };
18342}];
18343
18344/**
18345 * @ngdoc directive
18346 * @name ng.directive:ngInclude
18347 * @restrict ECA
18348 *
18349 * @description
18350 * Fetches, compiles and includes an external HTML fragment.
18351 *
18352 * By default, the template URL is restricted to the same domain and protocol as the
18353 * application document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
18354 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
18355 * you may either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist them} or
18356 * {@link ng.$sce#methods_trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
18357 * ng.$sce Strict Contextual Escaping}.
18358 *
18359 * In addition, the browser's
18360 * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
18361 * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
18362 * (CORS)} policy may further restrict whether the template is successfully loaded.
18363 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
18364 * access on some browsers.
18365 *
18366 * @animations
18367 * enter - animation is used to bring new content into the browser.
18368 * leave - animation is used to animate existing content away.
18369 *
18370 * The enter and leave animation occur concurrently.
18371 *
18372 * @scope
18373 * @priority 400
18374 *
18375 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
18376 *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
18377 * @param {string=} onload Expression to evaluate when a new partial is loaded.
18378 *
18379 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
18380 *                  $anchorScroll} to scroll the viewport after the content is loaded.
18381 *
18382 *                  - If the attribute is not set, disable scrolling.
18383 *                  - If the attribute is set without value, enable scrolling.
18384 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
18385 *
18386 * @example
18387  <example animations="true">
18388    <file name="index.html">
18389     <div ng-controller="Ctrl">
18390       <select ng-model="template" ng-options="t.name for t in templates">
18391        <option value="">(blank)</option>
18392       </select>
18393       url of the template: <tt>{{template.url}}</tt>
18394       <hr/>
18395       <div class="slide-animate-container">
18396         <div class="slide-animate" ng-include="template.url"></div>
18397       </div>
18398     </div>
18399    </file>
18400    <file name="script.js">
18401      function Ctrl($scope) {
18402        $scope.templates =
18403          [ { name: 'template1.html', url: 'template1.html'}
18404          , { name: 'template2.html', url: 'template2.html'} ];
18405        $scope.template = $scope.templates[0];
18406      }
18407     </file>
18408    <file name="template1.html">
18409      Content of template1.html
18410    </file>
18411    <file name="template2.html">
18412      Content of template2.html
18413    </file>
18414    <file name="animations.css">
18415      .slide-animate-container {
18416        position:relative;
18417        background:white;
18418        border:1px solid black;
18419        height:40px;
18420        overflow:hidden;
18421      }
18422
18423      .slide-animate {
18424        padding:10px;
18425      }
18426
18427      .slide-animate.ng-enter, .slide-animate.ng-leave {
18428        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18429        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18430
18431        position:absolute;
18432        top:0;
18433        left:0;
18434        right:0;
18435        bottom:0;
18436        display:block;
18437        padding:10px;
18438      }
18439
18440      .slide-animate.ng-enter {
18441        top:-50px;
18442      }
18443      .slide-animate.ng-enter.ng-enter-active {
18444        top:0;
18445      }
18446
18447      .slide-animate.ng-leave {
18448        top:0;
18449      }
18450      .slide-animate.ng-leave.ng-leave-active {
18451        top:50px;
18452      }
18453    </file>
18454    <file name="scenario.js">
18455      it('should load template1.html', function() {
18456       expect(element('.doc-example-live [ng-include]').text()).
18457         toMatch(/Content of template1.html/);
18458      });
18459      it('should load template2.html', function() {
18460       select('template').option('1');
18461       expect(element('.doc-example-live [ng-include]').text()).
18462         toMatch(/Content of template2.html/);
18463      });
18464      it('should change to blank', function() {
18465       select('template').option('');
18466       expect(element('.doc-example-live [ng-include]')).toBe(undefined);
18467      });
18468    </file>
18469  </example>
18470 */
18471
18472
18473/**
18474 * @ngdoc event
18475 * @name ng.directive:ngInclude#$includeContentRequested
18476 * @eventOf ng.directive:ngInclude
18477 * @eventType emit on the scope ngInclude was declared in
18478 * @description
18479 * Emitted every time the ngInclude content is requested.
18480 */
18481
18482
18483/**
18484 * @ngdoc event
18485 * @name ng.directive:ngInclude#$includeContentLoaded
18486 * @eventOf ng.directive:ngInclude
18487 * @eventType emit on the current ngInclude scope
18488 * @description
18489 * Emitted every time the ngInclude content is reloaded.
18490 */
18491var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
18492                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
18493  return {
18494    restrict: 'ECA',
18495    priority: 400,
18496    terminal: true,
18497    transclude: 'element',
18498    controller: angular.noop,
18499    compile: function(element, attr) {
18500      var srcExp = attr.ngInclude || attr.src,
18501          onloadExp = attr.onload || '',
18502          autoScrollExp = attr.autoscroll;
18503
18504      return function(scope, $element, $attr, ctrl, $transclude) {
18505        var changeCounter = 0,
18506            currentScope,
18507            currentElement;
18508
18509        var cleanupLastIncludeContent = function() {
18510          if (currentScope) {
18511            currentScope.$destroy();
18512            currentScope = null;
18513          }
18514          if(currentElement) {
18515            $animate.leave(currentElement);
18516            currentElement = null;
18517          }
18518        };
18519
18520        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
18521          var afterAnimation = function() {
18522            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
18523              $anchorScroll();
18524            }
18525          };
18526          var thisChangeId = ++changeCounter;
18527
18528          if (src) {
18529            $http.get(src, {cache: $templateCache}).success(function(response) {
18530              if (thisChangeId !== changeCounter) return;
18531              var newScope = scope.$new();
18532              ctrl.template = response;
18533
18534              // Note: This will also link all children of ng-include that were contained in the original
18535              // html. If that content contains controllers, ... they could pollute/change the scope.
18536              // However, using ng-include on an element with additional content does not make sense...
18537              // Note: We can't remove them in the cloneAttchFn of $transclude as that
18538              // function is called before linking the content, which would apply child
18539              // directives to non existing elements.
18540              var clone = $transclude(newScope, function(clone) {
18541                cleanupLastIncludeContent();
18542                $animate.enter(clone, null, $element, afterAnimation);
18543              });
18544
18545              currentScope = newScope;
18546              currentElement = clone;
18547
18548              currentScope.$emit('$includeContentLoaded');
18549              scope.$eval(onloadExp);
18550            }).error(function() {
18551              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
18552            });
18553            scope.$emit('$includeContentRequested');
18554          } else {
18555            cleanupLastIncludeContent();
18556            ctrl.template = null;
18557          }
18558        });
18559      };
18560    }
18561  };
18562}];
18563
18564// This directive is called during the $transclude call of the first `ngInclude` directive.
18565// It will replace and compile the content of the element with the loaded template.
18566// We need this directive so that the element content is already filled when
18567// the link function of another directive on the same element as ngInclude
18568// is called.
18569var ngIncludeFillContentDirective = ['$compile',
18570  function($compile) {
18571    return {
18572      restrict: 'ECA',
18573      priority: -400,
18574      require: 'ngInclude',
18575      link: function(scope, $element, $attr, ctrl) {
18576        $element.html(ctrl.template);
18577        $compile($element.contents())(scope);
18578      }
18579    };
18580  }];
18581
18582/**
18583 * @ngdoc directive
18584 * @name ng.directive:ngInit
18585 * @restrict AC
18586 *
18587 * @description
18588 * The `ngInit` directive allows you to evaluate an expression in the
18589 * current scope.
18590 *
18591 * <div class="alert alert-error">
18592 * The only appropriate use of `ngInit` is for aliasing special properties of
18593 * {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
18594 * should use {@link guide/controller controllers} rather than `ngInit`
18595 * to initialize values on a scope.
18596 * </div>
18597 * <div class="alert alert-warning">
18598 * **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
18599 * sure you have parenthesis for correct precedence:
18600 * <pre class="prettyprint">
18601 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
18602 * </pre>
18603 * </div>
18604 *
18605 * @priority 450
18606 *
18607 * @element ANY
18608 * @param {expression} ngInit {@link guide/expression Expression} to eval.
18609 *
18610 * @example
18611   <doc:example>
18612     <doc:source>
18613   <script>
18614     function Ctrl($scope) {
18615       $scope.list = [['a', 'b'], ['c', 'd']];
18616     }
18617   </script>
18618   <div ng-controller="Ctrl">
18619     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
18620       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
18621          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
18622       </div>
18623     </div>
18624   </div>
18625     </doc:source>
18626     <doc:scenario>
18627       it('should alias index positions', function() {
18628         expect(element('.example-init').text())
18629           .toBe('list[ 0 ][ 0 ] = a;' +
18630                 'list[ 0 ][ 1 ] = b;' +
18631                 'list[ 1 ][ 0 ] = c;' +
18632                 'list[ 1 ][ 1 ] = d;');
18633       });
18634     </doc:scenario>
18635   </doc:example>
18636 */
18637var ngInitDirective = ngDirective({
18638  priority: 450,
18639  compile: function() {
18640    return {
18641      pre: function(scope, element, attrs) {
18642        scope.$eval(attrs.ngInit);
18643      }
18644    };
18645  }
18646});
18647
18648/**
18649 * @ngdoc directive
18650 * @name ng.directive:ngNonBindable
18651 * @restrict AC
18652 * @priority 1000
18653 *
18654 * @description
18655 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
18656 * DOM element. This is useful if the element contains what appears to be Angular directives and
18657 * bindings but which should be ignored by Angular. This could be the case if you have a site that
18658 * displays snippets of code, for instance.
18659 *
18660 * @element ANY
18661 *
18662 * @example
18663 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
18664 * but the one wrapped in `ngNonBindable` is left alone.
18665 *
18666 * @example
18667    <doc:example>
18668      <doc:source>
18669        <div>Normal: {{1 + 2}}</div>
18670        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
18671      </doc:source>
18672      <doc:scenario>
18673       it('should check ng-non-bindable', function() {
18674         expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
18675         expect(using('.doc-example-live').element('div:last').text()).
18676           toMatch(/1 \+ 2/);
18677       });
18678      </doc:scenario>
18679    </doc:example>
18680 */
18681var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
18682
18683/**
18684 * @ngdoc directive
18685 * @name ng.directive:ngPluralize
18686 * @restrict EA
18687 *
18688 * @description
18689 * # Overview
18690 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
18691 * These rules are bundled with angular.js, but can be overridden
18692 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
18693 * by specifying the mappings between
18694 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18695 * plural categories} and the strings to be displayed.
18696 *
18697 * # Plural categories and explicit number rules
18698 * There are two
18699 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18700 * plural categories} in Angular's default en-US locale: "one" and "other".
18701 *
18702 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
18703 * any number that is not 1), an explicit number rule can only match one number. For example, the
18704 * explicit number rule for "3" matches the number 3. There are examples of plural categories
18705 * and explicit number rules throughout the rest of this documentation.
18706 *
18707 * # Configuring ngPluralize
18708 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
18709 * You can also provide an optional attribute, `offset`.
18710 *
18711 * The value of the `count` attribute can be either a string or an {@link guide/expression
18712 * Angular expression}; these are evaluated on the current scope for its bound value.
18713 *
18714 * The `when` attribute specifies the mappings between plural categories and the actual
18715 * string to be displayed. The value of the attribute should be a JSON object.
18716 *
18717 * The following example shows how to configure ngPluralize:
18718 *
18719 * <pre>
18720 * <ng-pluralize count="personCount"
18721                 when="{'0': 'Nobody is viewing.',
18722 *                      'one': '1 person is viewing.',
18723 *                      'other': '{} people are viewing.'}">
18724 * </ng-pluralize>
18725 *</pre>
18726 *
18727 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
18728 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
18729 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
18730 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
18731 * show "a dozen people are viewing".
18732 *
18733 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
18734 * into pluralized strings. In the previous example, Angular will replace `{}` with
18735 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
18736 * for <span ng-non-bindable>{{numberExpression}}</span>.
18737 *
18738 * # Configuring ngPluralize with offset
18739 * The `offset` attribute allows further customization of pluralized text, which can result in
18740 * a better user experience. For example, instead of the message "4 people are viewing this document",
18741 * you might display "John, Kate and 2 others are viewing this document".
18742 * The offset attribute allows you to offset a number by any desired value.
18743 * Let's take a look at an example:
18744 *
18745 * <pre>
18746 * <ng-pluralize count="personCount" offset=2
18747 *               when="{'0': 'Nobody is viewing.',
18748 *                      '1': '{{person1}} is viewing.',
18749 *                      '2': '{{person1}} and {{person2}} are viewing.',
18750 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
18751 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
18752 * </ng-pluralize>
18753 * </pre>
18754 *
18755 * Notice that we are still using two plural categories(one, other), but we added
18756 * three explicit number rules 0, 1 and 2.
18757 * When one person, perhaps John, views the document, "John is viewing" will be shown.
18758 * When three people view the document, no explicit number rule is found, so
18759 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
18760 * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
18761 * is shown.
18762 *
18763 * Note that when you specify offsets, you must provide explicit number rules for
18764 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
18765 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
18766 * plural categories "one" and "other".
18767 *
18768 * @param {string|expression} count The variable to be bounded to.
18769 * @param {string} when The mapping between plural category to its corresponding strings.
18770 * @param {number=} offset Offset to deduct from the total number.
18771 *
18772 * @example
18773    <doc:example>
18774      <doc:source>
18775        <script>
18776          function Ctrl($scope) {
18777            $scope.person1 = 'Igor';
18778            $scope.person2 = 'Misko';
18779            $scope.personCount = 1;
18780          }
18781        </script>
18782        <div ng-controller="Ctrl">
18783          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
18784          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
18785          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
18786
18787          <!--- Example with simple pluralization rules for en locale --->
18788          Without Offset:
18789          <ng-pluralize count="personCount"
18790                        when="{'0': 'Nobody is viewing.',
18791                               'one': '1 person is viewing.',
18792                               'other': '{} people are viewing.'}">
18793          </ng-pluralize><br>
18794
18795          <!--- Example with offset --->
18796          With Offset(2):
18797          <ng-pluralize count="personCount" offset=2
18798                        when="{'0': 'Nobody is viewing.',
18799                               '1': '{{person1}} is viewing.',
18800                               '2': '{{person1}} and {{person2}} are viewing.',
18801                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
18802                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
18803          </ng-pluralize>
18804        </div>
18805      </doc:source>
18806      <doc:scenario>
18807        it('should show correct pluralized string', function() {
18808          expect(element('.doc-example-live ng-pluralize:first').text()).
18809                                             toBe('1 person is viewing.');
18810          expect(element('.doc-example-live ng-pluralize:last').text()).
18811                                                toBe('Igor is viewing.');
18812
18813          using('.doc-example-live').input('personCount').enter('0');
18814          expect(element('.doc-example-live ng-pluralize:first').text()).
18815                                               toBe('Nobody is viewing.');
18816          expect(element('.doc-example-live ng-pluralize:last').text()).
18817                                              toBe('Nobody is viewing.');
18818
18819          using('.doc-example-live').input('personCount').enter('2');
18820          expect(element('.doc-example-live ng-pluralize:first').text()).
18821                                            toBe('2 people are viewing.');
18822          expect(element('.doc-example-live ng-pluralize:last').text()).
18823                              toBe('Igor and Misko are viewing.');
18824
18825          using('.doc-example-live').input('personCount').enter('3');
18826          expect(element('.doc-example-live ng-pluralize:first').text()).
18827                                            toBe('3 people are viewing.');
18828          expect(element('.doc-example-live ng-pluralize:last').text()).
18829                              toBe('Igor, Misko and one other person are viewing.');
18830
18831          using('.doc-example-live').input('personCount').enter('4');
18832          expect(element('.doc-example-live ng-pluralize:first').text()).
18833                                            toBe('4 people are viewing.');
18834          expect(element('.doc-example-live ng-pluralize:last').text()).
18835                              toBe('Igor, Misko and 2 other people are viewing.');
18836        });
18837
18838        it('should show data-binded names', function() {
18839          using('.doc-example-live').input('personCount').enter('4');
18840          expect(element('.doc-example-live ng-pluralize:last').text()).
18841              toBe('Igor, Misko and 2 other people are viewing.');
18842
18843          using('.doc-example-live').input('person1').enter('Di');
18844          using('.doc-example-live').input('person2').enter('Vojta');
18845          expect(element('.doc-example-live ng-pluralize:last').text()).
18846              toBe('Di, Vojta and 2 other people are viewing.');
18847        });
18848      </doc:scenario>
18849    </doc:example>
18850 */
18851var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
18852  var BRACE = /{}/g;
18853  return {
18854    restrict: 'EA',
18855    link: function(scope, element, attr) {
18856      var numberExp = attr.count,
18857          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
18858          offset = attr.offset || 0,
18859          whens = scope.$eval(whenExp) || {},
18860          whensExpFns = {},
18861          startSymbol = $interpolate.startSymbol(),
18862          endSymbol = $interpolate.endSymbol(),
18863          isWhen = /^when(Minus)?(.+)$/;
18864
18865      forEach(attr, function(expression, attributeName) {
18866        if (isWhen.test(attributeName)) {
18867          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
18868            element.attr(attr.$attr[attributeName]);
18869        }
18870      });
18871      forEach(whens, function(expression, key) {
18872        whensExpFns[key] =
18873          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
18874            offset + endSymbol));
18875      });
18876
18877      scope.$watch(function ngPluralizeWatch() {
18878        var value = parseFloat(scope.$eval(numberExp));
18879
18880        if (!isNaN(value)) {
18881          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
18882          //check it against pluralization rules in $locale service
18883          if (!(value in whens)) value = $locale.pluralCat(value - offset);
18884           return whensExpFns[value](scope, element, true);
18885        } else {
18886          return '';
18887        }
18888      }, function ngPluralizeWatchAction(newVal) {
18889        element.text(newVal);
18890      });
18891    }
18892  };
18893}];
18894
18895/**
18896 * @ngdoc directive
18897 * @name ng.directive:ngRepeat
18898 *
18899 * @description
18900 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
18901 * instance gets its own scope, where the given loop variable is set to the current collection item,
18902 * and `$index` is set to the item index or key.
18903 *
18904 * Special properties are exposed on the local scope of each template instance, including:
18905 *
18906 * | Variable  | Type            | Details                                                                     |
18907 * |-----------|-----------------|-----------------------------------------------------------------------------|
18908 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
18909 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
18910 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
18911 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
18912 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
18913 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
18914 *
18915 * Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
18916 * This may be useful when, for instance, nesting ngRepeats.
18917 *
18918 * # Special repeat start and end points
18919 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
18920 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
18921 * 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)
18922 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
18923 *
18924 * The example below makes use of this feature:
18925 * <pre>
18926 *   <header ng-repeat-start="item in items">
18927 *     Header {{ item }}
18928 *   </header>
18929 *   <div class="body">
18930 *     Body {{ item }}
18931 *   </div>
18932 *   <footer ng-repeat-end>
18933 *     Footer {{ item }}
18934 *   </footer>
18935 * </pre>
18936 *
18937 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
18938 * <pre>
18939 *   <header>
18940 *     Header A
18941 *   </header>
18942 *   <div class="body">
18943 *     Body A
18944 *   </div>
18945 *   <footer>
18946 *     Footer A
18947 *   </footer>
18948 *   <header>
18949 *     Header B
18950 *   </header>
18951 *   <div class="body">
18952 *     Body B
18953 *   </div>
18954 *   <footer>
18955 *     Footer B
18956 *   </footer>
18957 * </pre>
18958 *
18959 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
18960 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
18961 *
18962 * @animations
18963 * enter - when a new item is added to the list or when an item is revealed after a filter
18964 * leave - when an item is removed from the list or when an item is filtered out
18965 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
18966 *
18967 * @element ANY
18968 * @scope
18969 * @priority 1000
18970 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
18971 *   formats are currently supported:
18972 *
18973 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
18974 *     is a scope expression giving the collection to enumerate.
18975 *
18976 *     For example: `album in artist.albums`.
18977 *
18978 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
18979 *     and `expression` is the scope expression giving the collection to enumerate.
18980 *
18981 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
18982 *
18983 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
18984 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
18985 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
18986 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
18987 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
18988 *     before specifying a tracking expression.
18989 *
18990 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
18991 *     will be associated by item identity in the array.
18992 *
18993 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
18994 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
18995 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
18996 *     element in the same way in the DOM.
18997 *
18998 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
18999 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
19000 *     property is same.
19001 *
19002 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
19003 *     to items in conjunction with a tracking expression.
19004 *
19005 * @example
19006 * This example initializes the scope to a list of names and
19007 * then uses `ngRepeat` to display every person:
19008  <example animations="true">
19009    <file name="index.html">
19010      <div ng-init="friends = [
19011        {name:'John', age:25, gender:'boy'},
19012        {name:'Jessie', age:30, gender:'girl'},
19013        {name:'Johanna', age:28, gender:'girl'},
19014        {name:'Joy', age:15, gender:'girl'},
19015        {name:'Mary', age:28, gender:'girl'},
19016        {name:'Peter', age:95, gender:'boy'},
19017        {name:'Sebastian', age:50, gender:'boy'},
19018        {name:'Erika', age:27, gender:'girl'},
19019        {name:'Patrick', age:40, gender:'boy'},
19020        {name:'Samantha', age:60, gender:'girl'}
19021      ]">
19022        I have {{friends.length}} friends. They are:
19023        <input type="search" ng-model="q" placeholder="filter friends..." />
19024        <ul class="example-animate-container">
19025          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
19026            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
19027          </li>
19028        </ul>
19029      </div>
19030    </file>
19031    <file name="animations.css">
19032      .example-animate-container {
19033        background:white;
19034        border:1px solid black;
19035        list-style:none;
19036        margin:0;
19037        padding:0 10px;
19038      }
19039
19040      .animate-repeat {
19041        line-height:40px;
19042        list-style:none;
19043        box-sizing:border-box;
19044      }
19045
19046      .animate-repeat.ng-move,
19047      .animate-repeat.ng-enter,
19048      .animate-repeat.ng-leave {
19049        -webkit-transition:all linear 0.5s;
19050        transition:all linear 0.5s;
19051      }
19052
19053      .animate-repeat.ng-leave.ng-leave-active,
19054      .animate-repeat.ng-move,
19055      .animate-repeat.ng-enter {
19056        opacity:0;
19057        max-height:0;
19058      }
19059
19060      .animate-repeat.ng-leave,
19061      .animate-repeat.ng-move.ng-move-active,
19062      .animate-repeat.ng-enter.ng-enter-active {
19063        opacity:1;
19064        max-height:40px;
19065      }
19066    </file>
19067    <file name="scenario.js">
19068       it('should render initial data set', function() {
19069         var r = using('.doc-example-live').repeater('ul li');
19070         expect(r.count()).toBe(10);
19071         expect(r.row(0)).toEqual(["1","John","25"]);
19072         expect(r.row(1)).toEqual(["2","Jessie","30"]);
19073         expect(r.row(9)).toEqual(["10","Samantha","60"]);
19074         expect(binding('friends.length')).toBe("10");
19075       });
19076
19077       it('should update repeater when filter predicate changes', function() {
19078         var r = using('.doc-example-live').repeater('ul li');
19079         expect(r.count()).toBe(10);
19080
19081         input('q').enter('ma');
19082
19083         expect(r.count()).toBe(2);
19084         expect(r.row(0)).toEqual(["1","Mary","28"]);
19085         expect(r.row(1)).toEqual(["2","Samantha","60"]);
19086       });
19087      </file>
19088    </example>
19089 */
19090var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
19091  var NG_REMOVED = '$$NG_REMOVED';
19092  var ngRepeatMinErr = minErr('ngRepeat');
19093  return {
19094    transclude: 'element',
19095    priority: 1000,
19096    terminal: true,
19097    $$tlb: true,
19098    link: function($scope, $element, $attr, ctrl, $transclude){
19099        var expression = $attr.ngRepeat;
19100        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
19101          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
19102          lhs, rhs, valueIdentifier, keyIdentifier,
19103          hashFnLocals = {$id: hashKey};
19104
19105        if (!match) {
19106          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
19107            expression);
19108        }
19109
19110        lhs = match[1];
19111        rhs = match[2];
19112        trackByExp = match[3];
19113
19114        if (trackByExp) {
19115          trackByExpGetter = $parse(trackByExp);
19116          trackByIdExpFn = function(key, value, index) {
19117            // assign key, value, and $index to the locals so that they can be used in hash functions
19118            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
19119            hashFnLocals[valueIdentifier] = value;
19120            hashFnLocals.$index = index;
19121            return trackByExpGetter($scope, hashFnLocals);
19122          };
19123        } else {
19124          trackByIdArrayFn = function(key, value) {
19125            return hashKey(value);
19126          };
19127          trackByIdObjFn = function(key) {
19128            return key;
19129          };
19130        }
19131
19132        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
19133        if (!match) {
19134          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
19135                                                                    lhs);
19136        }
19137        valueIdentifier = match[3] || match[1];
19138        keyIdentifier = match[2];
19139
19140        // Store a list of elements from previous run. This is a hash where key is the item from the
19141        // iterator, and the value is objects with following properties.
19142        //   - scope: bound scope
19143        //   - element: previous element.
19144        //   - index: position
19145        var lastBlockMap = {};
19146
19147        //watch props
19148        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
19149          var index, length,
19150              previousNode = $element[0],     // current position of the node
19151              nextNode,
19152              // Same as lastBlockMap but it has the current state. It will become the
19153              // lastBlockMap on the next iteration.
19154              nextBlockMap = {},
19155              arrayLength,
19156              childScope,
19157              key, value, // key/value of iteration
19158              trackById,
19159              trackByIdFn,
19160              collectionKeys,
19161              block,       // last object information {scope, element, id}
19162              nextBlockOrder = [],
19163              elementsToRemove;
19164
19165
19166          if (isArrayLike(collection)) {
19167            collectionKeys = collection;
19168            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
19169          } else {
19170            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
19171            // if object, extract keys, sort them and use to determine order of iteration over obj props
19172            collectionKeys = [];
19173            for (key in collection) {
19174              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
19175                collectionKeys.push(key);
19176              }
19177            }
19178            collectionKeys.sort();
19179          }
19180
19181          arrayLength = collectionKeys.length;
19182
19183          // locate existing items
19184          length = nextBlockOrder.length = collectionKeys.length;
19185          for(index = 0; index < length; index++) {
19186           key = (collection === collectionKeys) ? index : collectionKeys[index];
19187           value = collection[key];
19188           trackById = trackByIdFn(key, value, index);
19189           assertNotHasOwnProperty(trackById, '`track by` id');
19190           if(lastBlockMap.hasOwnProperty(trackById)) {
19191             block = lastBlockMap[trackById];
19192             delete lastBlockMap[trackById];
19193             nextBlockMap[trackById] = block;
19194             nextBlockOrder[index] = block;
19195           } else if (nextBlockMap.hasOwnProperty(trackById)) {
19196             // restore lastBlockMap
19197             forEach(nextBlockOrder, function(block) {
19198               if (block && block.scope) lastBlockMap[block.id] = block;
19199             });
19200             // This is a duplicate and we need to throw an error
19201             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
19202                                                                                                                                                    expression,       trackById);
19203           } else {
19204             // new never before seen block
19205             nextBlockOrder[index] = { id: trackById };
19206             nextBlockMap[trackById] = false;
19207           }
19208         }
19209
19210          // remove existing items
19211          for (key in lastBlockMap) {
19212            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
19213            if (lastBlockMap.hasOwnProperty(key)) {
19214              block = lastBlockMap[key];
19215              elementsToRemove = getBlockElements(block.clone);
19216              $animate.leave(elementsToRemove);
19217              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
19218              block.scope.$destroy();
19219            }
19220          }
19221
19222          // we are not using forEach for perf reasons (trying to avoid #call)
19223          for (index = 0, length = collectionKeys.length; index < length; index++) {
19224            key = (collection === collectionKeys) ? index : collectionKeys[index];
19225            value = collection[key];
19226            block = nextBlockOrder[index];
19227            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
19228
19229            if (block.scope) {
19230              // if we have already seen this object, then we need to reuse the
19231              // associated scope/element
19232              childScope = block.scope;
19233
19234              nextNode = previousNode;
19235              do {
19236                nextNode = nextNode.nextSibling;
19237              } while(nextNode && nextNode[NG_REMOVED]);
19238
19239              if (getBlockStart(block) != nextNode) {
19240                // existing item which got moved
19241                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
19242              }
19243              previousNode = getBlockEnd(block);
19244            } else {
19245              // new item which we don't know about
19246              childScope = $scope.$new();
19247            }
19248
19249            childScope[valueIdentifier] = value;
19250            if (keyIdentifier) childScope[keyIdentifier] = key;
19251            childScope.$index = index;
19252            childScope.$first = (index === 0);
19253            childScope.$last = (index === (arrayLength - 1));
19254            childScope.$middle = !(childScope.$first || childScope.$last);
19255            // jshint bitwise: false
19256            childScope.$odd = !(childScope.$even = (index&1) === 0);
19257            // jshint bitwise: true
19258
19259            if (!block.scope) {
19260              $transclude(childScope, function(clone) {
19261                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
19262                $animate.enter(clone, null, jqLite(previousNode));
19263                previousNode = clone;
19264                block.scope = childScope;
19265                // Note: We only need the first/last node of the cloned nodes.
19266                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19267                // by a directive with templateUrl when it's template arrives.
19268                block.clone = clone;
19269                nextBlockMap[block.id] = block;
19270              });
19271            }
19272          }
19273          lastBlockMap = nextBlockMap;
19274        });
19275    }
19276  };
19277
19278  function getBlockStart(block) {
19279    return block.clone[0];
19280  }
19281
19282  function getBlockEnd(block) {
19283    return block.clone[block.clone.length - 1];
19284  }
19285}];
19286
19287/**
19288 * @ngdoc directive
19289 * @name ng.directive:ngShow
19290 *
19291 * @description
19292 * The `ngShow` directive shows or hides the given HTML element based on the expression
19293 * provided to the ngShow attribute. The element is shown or hidden by removing or adding
19294 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
19295 * in AngularJS and sets the display style to none (using an !important flag).
19296 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
19297 *
19298 * <pre>
19299 * <!-- when $scope.myValue is truthy (element is visible) -->
19300 * <div ng-show="myValue"></div>
19301 *
19302 * <!-- when $scope.myValue is falsy (element is hidden) -->
19303 * <div ng-show="myValue" class="ng-hide"></div>
19304 * </pre>
19305 *
19306 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
19307 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
19308 * from the element causing the element not to appear hidden.
19309 *
19310 * ## Why is !important used?
19311 *
19312 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
19313 * can be easily overridden by heavier selectors. For example, something as simple
19314 * as changing the display style on a HTML list item would make hidden elements appear visible.
19315 * This also becomes a bigger issue when dealing with CSS frameworks.
19316 *
19317 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
19318 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
19319 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
19320 *
19321 * ### Overriding .ng-hide
19322 *
19323 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
19324 * restating the styles for the .ng-hide class in CSS:
19325 * <pre>
19326 * .ng-hide {
19327 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
19328 *   display:block!important;
19329 *
19330 *   //this is just another form of hiding an element
19331 *   position:absolute;
19332 *   top:-9999px;
19333 *   left:-9999px;
19334 * }
19335 * </pre>
19336 *
19337 * Just remember to include the important flag so the CSS override will function.
19338 *
19339 * <div class="alert alert-warning">
19340 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
19341 * "f" / "0" / "false" / "no" / "n" / "[]"
19342 * </div>
19343 * 
19344 * ## A note about animations with ngShow
19345 *
19346 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
19347 * is true and false. This system works like the animation system present with ngClass except that
19348 * you must also include the !important flag to override the display property
19349 * so that you can perform an animation when the element is hidden during the time of the animation.
19350 *
19351 * <pre>
19352 * //
19353 * //a working example can be found at the bottom of this page
19354 * //
19355 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
19356 *   transition:0.5s linear all;
19357 *   display:block!important;
19358 * }
19359 *
19360 * .my-element.ng-hide-add { ... }
19361 * .my-element.ng-hide-add.ng-hide-add-active { ... }
19362 * .my-element.ng-hide-remove { ... }
19363 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
19364 * </pre>
19365 *
19366 * @animations
19367 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
19368 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
19369 *
19370 * @element ANY
19371 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
19372 *     then the element is shown or hidden respectively.
19373 *
19374 * @example
19375  <example animations="true">
19376    <file name="index.html">
19377      Click me: <input type="checkbox" ng-model="checked"><br/>
19378      <div>
19379        Show:
19380        <div class="check-element animate-show" ng-show="checked">
19381          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
19382        </div>
19383      </div>
19384      <div>
19385        Hide:
19386        <div class="check-element animate-show" ng-hide="checked">
19387          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
19388        </div>
19389      </div>
19390    </file>
19391    <file name="animations.css">
19392      .animate-show {
19393        -webkit-transition:all linear 0.5s;
19394        transition:all linear 0.5s;
19395        line-height:20px;
19396        opacity:1;
19397        padding:10px;
19398        border:1px solid black;
19399        background:white;
19400      }
19401
19402      .animate-show.ng-hide-add,
19403      .animate-show.ng-hide-remove {
19404        display:block!important;
19405      }
19406
19407      .animate-show.ng-hide {
19408        line-height:0;
19409        opacity:0;
19410        padding:0 10px;
19411      }
19412
19413      .check-element {
19414        padding:10px;
19415        border:1px solid black;
19416        background:white;
19417      }
19418    </file>
19419    <file name="scenario.js">
19420       it('should check ng-show / ng-hide', function() {
19421         expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
19422         expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
19423
19424         input('checked').check();
19425
19426         expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
19427         expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
19428       });
19429    </file>
19430  </example>
19431 */
19432var ngShowDirective = ['$animate', function($animate) {
19433  return function(scope, element, attr) {
19434    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
19435      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
19436    });
19437  };
19438}];
19439
19440
19441/**
19442 * @ngdoc directive
19443 * @name ng.directive:ngHide
19444 *
19445 * @description
19446 * The `ngHide` directive shows or hides the given HTML element based on the expression
19447 * provided to the ngHide attribute. The element is shown or hidden by removing or adding
19448 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
19449 * in AngularJS and sets the display style to none (using an !important flag).
19450 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
19451 *
19452 * <pre>
19453 * <!-- when $scope.myValue is truthy (element is hidden) -->
19454 * <div ng-hide="myValue"></div>
19455 *
19456 * <!-- when $scope.myValue is falsy (element is visible) -->
19457 * <div ng-hide="myValue" class="ng-hide"></div>
19458 * </pre>
19459 *
19460 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
19461 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
19462 * from the element causing the element not to appear hidden.
19463 *
19464 * ## Why is !important used?
19465 *
19466 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
19467 * can be easily overridden by heavier selectors. For example, something as simple
19468 * as changing the display style on a HTML list item would make hidden elements appear visible.
19469 * This also becomes a bigger issue when dealing with CSS frameworks.
19470 *
19471 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
19472 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
19473 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
19474 *
19475 * ### Overriding .ng-hide
19476 *
19477 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
19478 * restating the styles for the .ng-hide class in CSS:
19479 * <pre>
19480 * .ng-hide {
19481 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
19482 *   display:block!important;
19483 *
19484 *   //this is just another form of hiding an element
19485 *   position:absolute;
19486 *   top:-9999px;
19487 *   left:-9999px;
19488 * }
19489 * </pre>
19490 *
19491 * Just remember to include the important flag so the CSS override will function.
19492 * 
19493 * <div class="alert alert-warning">
19494 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
19495 * "f" / "0" / "false" / "no" / "n" / "[]"
19496 * </div>
19497 *
19498 * ## A note about animations with ngHide
19499 *
19500 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
19501 * is true and false. This system works like the animation system present with ngClass, except that
19502 * you must also include the !important flag to override the display property so
19503 * that you can perform an animation when the element is hidden during the time of the animation.
19504 *
19505 * <pre>
19506 * //
19507 * //a working example can be found at the bottom of this page
19508 * //
19509 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
19510 *   transition:0.5s linear all;
19511 *   display:block!important;
19512 * }
19513 *
19514 * .my-element.ng-hide-add { ... }
19515 * .my-element.ng-hide-add.ng-hide-add-active { ... }
19516 * .my-element.ng-hide-remove { ... }
19517 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
19518 * </pre>
19519 *
19520 * @animations
19521 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
19522 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
19523 *
19524 * @element ANY
19525 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
19526 *     the element is shown or hidden respectively.
19527 *
19528 * @example
19529  <example animations="true">
19530    <file name="index.html">
19531      Click me: <input type="checkbox" ng-model="checked"><br/>
19532      <div>
19533        Show:
19534        <div class="check-element animate-hide" ng-show="checked">
19535          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
19536        </div>
19537      </div>
19538      <div>
19539        Hide:
19540        <div class="check-element animate-hide" ng-hide="checked">
19541          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
19542        </div>
19543      </div>
19544    </file>
19545    <file name="animations.css">
19546      .animate-hide {
19547        -webkit-transition:all linear 0.5s;
19548        transition:all linear 0.5s;
19549        line-height:20px;
19550        opacity:1;
19551        padding:10px;
19552        border:1px solid black;
19553        background:white;
19554      }
19555
19556      .animate-hide.ng-hide-add,
19557      .animate-hide.ng-hide-remove {
19558        display:block!important;
19559      }
19560
19561      .animate-hide.ng-hide {
19562        line-height:0;
19563        opacity:0;
19564        padding:0 10px;
19565      }
19566
19567      .check-element {
19568        padding:10px;
19569        border:1px solid black;
19570        background:white;
19571      }
19572    </file>
19573    <file name="scenario.js">
19574       it('should check ng-show / ng-hide', function() {
19575         expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
19576         expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
19577
19578         input('checked').check();
19579
19580         expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
19581         expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
19582       });
19583    </file>
19584  </example>
19585 */
19586var ngHideDirective = ['$animate', function($animate) {
19587  return function(scope, element, attr) {
19588    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
19589      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
19590    });
19591  };
19592}];
19593
19594/**
19595 * @ngdoc directive
19596 * @name ng.directive:ngStyle
19597 * @restrict AC
19598 *
19599 * @description
19600 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
19601 *
19602 * @element ANY
19603 * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
19604 *      object whose keys are CSS style names and values are corresponding values for those CSS
19605 *      keys.
19606 *
19607 * @example
19608   <example>
19609     <file name="index.html">
19610        <input type="button" value="set" ng-click="myStyle={color:'red'}">
19611        <input type="button" value="clear" ng-click="myStyle={}">
19612        <br/>
19613        <span ng-style="myStyle">Sample Text</span>
19614        <pre>myStyle={{myStyle}}</pre>
19615     </file>
19616     <file name="style.css">
19617       span {
19618         color: black;
19619       }
19620     </file>
19621     <file name="scenario.js">
19622       it('should check ng-style', function() {
19623         expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
19624         element('.doc-example-live :button[value=set]').click();
19625         expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
19626         element('.doc-example-live :button[value=clear]').click();
19627         expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
19628       });
19629     </file>
19630   </example>
19631 */
19632var ngStyleDirective = ngDirective(function(scope, element, attr) {
19633  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
19634    if (oldStyles && (newStyles !== oldStyles)) {
19635      forEach(oldStyles, function(val, style) { element.css(style, '');});
19636    }
19637    if (newStyles) element.css(newStyles);
19638  }, true);
19639});
19640
19641/**
19642 * @ngdoc directive
19643 * @name ng.directive:ngSwitch
19644 * @restrict EA
19645 *
19646 * @description
19647 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
19648 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
19649 * as specified in the template.
19650 *
19651 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
19652 * from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
19653 * matches the value obtained from the evaluated expression. In other words, you define a container element
19654 * (where you place the directive), place an expression on the **`on="..."` attribute**
19655 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
19656 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
19657 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
19658 * attribute is displayed.
19659 *
19660 * <div class="alert alert-info">
19661 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
19662 * as literal string values to match against.
19663 * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
19664 * value of the expression `$scope.someVal`.
19665 * </div>
19666
19667 * @animations
19668 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
19669 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
19670 *
19671 * @usage
19672 * <ANY ng-switch="expression">
19673 *   <ANY ng-switch-when="matchValue1">...</ANY>
19674 *   <ANY ng-switch-when="matchValue2">...</ANY>
19675 *   <ANY ng-switch-default>...</ANY>
19676 * </ANY>
19677 *
19678 *
19679 * @scope
19680 * @priority 800
19681 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
19682 * @paramDescription
19683 * On child elements add:
19684 *
19685 * * `ngSwitchWhen`: the case statement to match against. If match then this
19686 *   case will be displayed. If the same match appears multiple times, all the
19687 *   elements will be displayed.
19688 * * `ngSwitchDefault`: the default case when no other case match. If there
19689 *   are multiple default cases, all of them will be displayed when no other
19690 *   case match.
19691 *
19692 *
19693 * @example
19694  <example animations="true">
19695    <file name="index.html">
19696      <div ng-controller="Ctrl">
19697        <select ng-model="selection" ng-options="item for item in items">
19698        </select>
19699        <tt>selection={{selection}}</tt>
19700        <hr/>
19701        <div class="animate-switch-container"
19702          ng-switch on="selection">
19703            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
19704            <div class="animate-switch" ng-switch-when="home">Home Span</div>
19705            <div class="animate-switch" ng-switch-default>default</div>
19706        </div>
19707      </div>
19708    </file>
19709    <file name="script.js">
19710      function Ctrl($scope) {
19711        $scope.items = ['settings', 'home', 'other'];
19712        $scope.selection = $scope.items[0];
19713      }
19714    </file>
19715    <file name="animations.css">
19716      .animate-switch-container {
19717        position:relative;
19718        background:white;
19719        border:1px solid black;
19720        height:40px;
19721        overflow:hidden;
19722      }
19723
19724      .animate-switch {
19725        padding:10px;
19726      }
19727
19728      .animate-switch.ng-animate {
19729        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19730        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19731
19732        position:absolute;
19733        top:0;
19734        left:0;
19735        right:0;
19736        bottom:0;
19737      }
19738
19739      .animate-switch.ng-leave.ng-leave-active,
19740      .animate-switch.ng-enter {
19741        top:-50px;
19742      }
19743      .animate-switch.ng-leave,
19744      .animate-switch.ng-enter.ng-enter-active {
19745        top:0;
19746      }
19747    </file>
19748    <file name="scenario.js">
19749      it('should start in settings', function() {
19750        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
19751      });
19752      it('should change to home', function() {
19753        select('selection').option('home');
19754        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
19755      });
19756      it('should select default', function() {
19757        select('selection').option('other');
19758        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
19759      });
19760    </file>
19761  </example>
19762 */
19763var ngSwitchDirective = ['$animate', function($animate) {
19764  return {
19765    restrict: 'EA',
19766    require: 'ngSwitch',
19767
19768    // asks for $scope to fool the BC controller module
19769    controller: ['$scope', function ngSwitchController() {
19770     this.cases = {};
19771    }],
19772    link: function(scope, element, attr, ngSwitchController) {
19773      var watchExpr = attr.ngSwitch || attr.on,
19774          selectedTranscludes,
19775          selectedElements,
19776          selectedScopes = [];
19777
19778      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
19779        for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
19780          selectedScopes[i].$destroy();
19781          $animate.leave(selectedElements[i]);
19782        }
19783
19784        selectedElements = [];
19785        selectedScopes = [];
19786
19787        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
19788          scope.$eval(attr.change);
19789          forEach(selectedTranscludes, function(selectedTransclude) {
19790            var selectedScope = scope.$new();
19791            selectedScopes.push(selectedScope);
19792            selectedTransclude.transclude(selectedScope, function(caseElement) {
19793              var anchor = selectedTransclude.element;
19794
19795              selectedElements.push(caseElement);
19796              $animate.enter(caseElement, anchor.parent(), anchor);
19797            });
19798          });
19799        }
19800      });
19801    }
19802  };
19803}];
19804
19805var ngSwitchWhenDirective = ngDirective({
19806  transclude: 'element',
19807  priority: 800,
19808  require: '^ngSwitch',
19809  link: function(scope, element, attrs, ctrl, $transclude) {
19810    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
19811    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
19812  }
19813});
19814
19815var ngSwitchDefaultDirective = ngDirective({
19816  transclude: 'element',
19817  priority: 800,
19818  require: '^ngSwitch',
19819  link: function(scope, element, attr, ctrl, $transclude) {
19820    ctrl.cases['?'] = (ctrl.cases['?'] || []);
19821    ctrl.cases['?'].push({ transclude: $transclude, element: element });
19822   }
19823});
19824
19825/**
19826 * @ngdoc directive
19827 * @name ng.directive:ngTransclude
19828 * @restrict AC
19829 *
19830 * @description
19831 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
19832 *
19833 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
19834 *
19835 * @element ANY
19836 *
19837 * @example
19838   <doc:example module="transclude">
19839     <doc:source>
19840       <script>
19841         function Ctrl($scope) {
19842           $scope.title = 'Lorem Ipsum';
19843           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
19844         }
19845
19846         angular.module('transclude', [])
19847          .directive('pane', function(){
19848             return {
19849               restrict: 'E',
19850               transclude: true,
19851               scope: { title:'@' },
19852               template: '<div style="border: 1px solid black;">' +
19853                           '<div style="background-color: gray">{{title}}</div>' +
19854                           '<div ng-transclude></div>' +
19855                         '</div>'
19856             };
19857         });
19858       </script>
19859       <div ng-controller="Ctrl">
19860         <input ng-model="title"><br>
19861         <textarea ng-model="text"></textarea> <br/>
19862         <pane title="{{title}}">{{text}}</pane>
19863       </div>
19864     </doc:source>
19865     <doc:scenario>
19866        it('should have transcluded', function() {
19867          input('title').enter('TITLE');
19868          input('text').enter('TEXT');
19869          expect(binding('title')).toEqual('TITLE');
19870          expect(binding('text')).toEqual('TEXT');
19871        });
19872     </doc:scenario>
19873   </doc:example>
19874 *
19875 */
19876var ngTranscludeDirective = ngDirective({
19877  controller: ['$element', '$transclude', function($element, $transclude) {
19878    if (!$transclude) {
19879      throw minErr('ngTransclude')('orphan',
19880          'Illegal use of ngTransclude directive in the template! ' +
19881          'No parent directive that requires a transclusion found. ' +
19882          'Element: {0}',
19883          startingTag($element));
19884    }
19885
19886    // remember the transclusion fn but call it during linking so that we don't process transclusion before directives on
19887    // the parent element even when the transclusion replaces the current element. (we can't use priority here because
19888    // that applies only to compile fns and not controllers
19889    this.$transclude = $transclude;
19890  }],
19891
19892  link: function($scope, $element, $attrs, controller) {
19893    controller.$transclude(function(clone) {
19894      $element.empty();
19895      $element.append(clone);
19896    });
19897  }
19898});
19899
19900/**
19901 * @ngdoc directive
19902 * @name ng.directive:script
19903 * @restrict E
19904 *
19905 * @description
19906 * Load the content of a `<script>` element into {@link api/ng.$templateCache `$templateCache`}, so that the
19907 * template can be used by {@link api/ng.directive:ngInclude `ngInclude`},
19908 * {@link api/ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
19909 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
19910 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
19911 *
19912 * @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
19913 * @param {string} id Cache name of the template.
19914 *
19915 * @example
19916  <doc:example>
19917    <doc:source>
19918      <script type="text/ng-template" id="/tpl.html">
19919        Content of the template.
19920      </script>
19921
19922      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
19923      <div id="tpl-content" ng-include src="currentTpl"></div>
19924    </doc:source>
19925    <doc:scenario>
19926      it('should load template defined inside script tag', function() {
19927        element('#tpl-link').click();
19928        expect(element('#tpl-content').text()).toMatch(/Content of the template/);
19929      });
19930    </doc:scenario>
19931  </doc:example>
19932 */
19933var scriptDirective = ['$templateCache', function($templateCache) {
19934  return {
19935    restrict: 'E',
19936    terminal: true,
19937    compile: function(element, attr) {
19938      if (attr.type == 'text/ng-template') {
19939        var templateUrl = attr.id,
19940            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
19941            text = element[0].text;
19942
19943        $templateCache.put(templateUrl, text);
19944      }
19945    }
19946  };
19947}];
19948
19949var ngOptionsMinErr = minErr('ngOptions');
19950/**
19951 * @ngdoc directive
19952 * @name ng.directive:select
19953 * @restrict E
19954 *
19955 * @description
19956 * HTML `SELECT` element with angular data-binding.
19957 *
19958 * # `ngOptions`
19959 *
19960 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
19961 * elements for the `<select>` element using the array or object obtained by evaluating the
19962 * `ngOptions` comprehension_expression.
19963 *
19964 * When an item in the `<select>` menu is selected, the array element or object property
19965 * represented by the selected option will be bound to the model identified by the `ngModel`
19966 * directive.
19967 *
19968 * <div class="alert alert-warning">
19969 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
19970 * array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
19971 * </div>
19972 *
19973 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
19974 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
19975 * option. See example below for demonstration.
19976 *
19977 * <div class="alert alert-warning">
19978 * **Note:** `ngOptions` provides iterator facility for `<option>` element which should be used instead
19979 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
19980 * `select` model to be bound to a non-string value. This is because an option element can only
19981 * be bound to string values at present.
19982 * </div>
19983 *
19984 * @param {string} ngModel Assignable angular expression to data-bind to.
19985 * @param {string=} name Property name of the form under which the control is published.
19986 * @param {string=} required The control is considered valid only if value is entered.
19987 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19988 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19989 *    `required` when you want to data-bind to the `required` attribute.
19990 * @param {comprehension_expression=} ngOptions in one of the following forms:
19991 *
19992 *   * for array data sources:
19993 *     * `label` **`for`** `value` **`in`** `array`
19994 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
19995 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
19996 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
19997 *   * for object data sources:
19998 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
19999 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20000 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
20001 *     * `select` **`as`** `label` **`group by`** `group`
20002 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
20003 *
20004 * Where:
20005 *
20006 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
20007 *   * `value`: local variable which will refer to each item in the `array` or each property value
20008 *      of `object` during iteration.
20009 *   * `key`: local variable which will refer to a property name in `object` during iteration.
20010 *   * `label`: The result of this expression will be the label for `<option>` element. The
20011 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
20012 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
20013 *      element. If not specified, `select` expression will default to `value`.
20014 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
20015 *      DOM element.
20016 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
20017 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
20018 *     `value` variable (e.g. `value.propertyName`).
20019 *
20020 * @example
20021    <doc:example>
20022      <doc:source>
20023        <script>
20024        function MyCntrl($scope) {
20025          $scope.colors = [
20026            {name:'black', shade:'dark'},
20027            {name:'white', shade:'light'},
20028            {name:'red', shade:'dark'},
20029            {name:'blue', shade:'dark'},
20030            {name:'yellow', shade:'light'}
20031          ];
20032          $scope.color = $scope.colors[2]; // red
20033        }
20034        </script>
20035        <div ng-controller="MyCntrl">
20036          <ul>
20037            <li ng-repeat="color in colors">
20038              Name: <input ng-model="color.name">
20039              [<a href ng-click="colors.splice($index, 1)">X</a>]
20040            </li>
20041            <li>
20042              [<a href ng-click="colors.push({})">add</a>]
20043            </li>
20044          </ul>
20045          <hr/>
20046          Color (null not allowed):
20047          <select ng-model="color" ng-options="c.name for c in colors"></select><br>
20048
20049          Color (null allowed):
20050          <span  class="nullable">
20051            <select ng-model="color" ng-options="c.name for c in colors">
20052              <option value="">-- choose color --</option>
20053            </select>
20054          </span><br/>
20055
20056          Color grouped by shade:
20057          <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
20058          </select><br/>
20059
20060
20061          Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
20062          <hr/>
20063          Currently selected: {{ {selected_color:color}  }}
20064          <div style="border:solid 1px black; height:20px"
20065               ng-style="{'background-color':color.name}">
20066          </div>
20067        </div>
20068      </doc:source>
20069      <doc:scenario>
20070         it('should check ng-options', function() {
20071           expect(binding('{selected_color:color}')).toMatch('red');
20072           select('color').option('0');
20073           expect(binding('{selected_color:color}')).toMatch('black');
20074           using('.nullable').select('color').option('');
20075           expect(binding('{selected_color:color}')).toMatch('null');
20076         });
20077      </doc:scenario>
20078    </doc:example>
20079 */
20080
20081var ngOptionsDirective = valueFn({ terminal: true });
20082// jshint maxlen: false
20083var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
20084                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
20085  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]+?))?$/,
20086      nullModelCtrl = {$setViewValue: noop};
20087// jshint maxlen: 100
20088
20089  return {
20090    restrict: 'E',
20091    require: ['select', '?ngModel'],
20092    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
20093      var self = this,
20094          optionsMap = {},
20095          ngModelCtrl = nullModelCtrl,
20096          nullOption,
20097          unknownOption;
20098
20099
20100      self.databound = $attrs.ngModel;
20101
20102
20103      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
20104        ngModelCtrl = ngModelCtrl_;
20105        nullOption = nullOption_;
20106        unknownOption = unknownOption_;
20107      };
20108
20109
20110      self.addOption = function(value) {
20111        assertNotHasOwnProperty(value, '"option value"');
20112        optionsMap[value] = true;
20113
20114        if (ngModelCtrl.$viewValue == value) {
20115          $element.val(value);
20116          if (unknownOption.parent()) unknownOption.remove();
20117        }
20118      };
20119
20120
20121      self.removeOption = function(value) {
20122        if (this.hasOption(value)) {
20123          delete optionsMap[value];
20124          if (ngModelCtrl.$viewValue == value) {
20125            this.renderUnknownOption(value);
20126          }
20127        }
20128      };
20129
20130
20131      self.renderUnknownOption = function(val) {
20132        var unknownVal = '? ' + hashKey(val) + ' ?';
20133        unknownOption.val(unknownVal);
20134        $element.prepend(unknownOption);
20135        $element.val(unknownVal);
20136        unknownOption.prop('selected', true); // needed for IE
20137      };
20138
20139
20140      self.hasOption = function(value) {
20141        return optionsMap.hasOwnProperty(value);
20142      };
20143
20144      $scope.$on('$destroy', function() {
20145        // disable unknown option so that we don't do work when the whole select is being destroyed
20146        self.renderUnknownOption = noop;
20147      });
20148    }],
20149
20150    link: function(scope, element, attr, ctrls) {
20151      // if ngModel is not defined, we don't need to do anything
20152      if (!ctrls[1]) return;
20153
20154      var selectCtrl = ctrls[0],
20155          ngModelCtrl = ctrls[1],
20156          multiple = attr.multiple,
20157          optionsExp = attr.ngOptions,
20158          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
20159          emptyOption,
20160          // we can't just jqLite('<option>') since jqLite is not smart enough
20161          // to create it in <select> and IE barfs otherwise.
20162          optionTemplate = jqLite(document.createElement('option')),
20163          optGroupTemplate =jqLite(document.createElement('optgroup')),
20164          unknownOption = optionTemplate.clone();
20165
20166      // find "null" option
20167      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
20168        if (children[i].value === '') {
20169          emptyOption = nullOption = children.eq(i);
20170          break;
20171        }
20172      }
20173
20174      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
20175
20176      // required validator
20177      if (multiple) {
20178        ngModelCtrl.$isEmpty = function(value) {
20179          return !value || value.length === 0;
20180        };
20181      }
20182
20183      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
20184      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
20185      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
20186
20187
20188      ////////////////////////////
20189
20190
20191
20192      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
20193        ngModelCtrl.$render = function() {
20194          var viewValue = ngModelCtrl.$viewValue;
20195
20196          if (selectCtrl.hasOption(viewValue)) {
20197            if (unknownOption.parent()) unknownOption.remove();
20198            selectElement.val(viewValue);
20199            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
20200          } else {
20201            if (isUndefined(viewValue) && emptyOption) {
20202              selectElement.val('');
20203            } else {
20204              selectCtrl.renderUnknownOption(viewValue);
20205            }
20206          }
20207        };
20208
20209        selectElement.on('change', function() {
20210          scope.$apply(function() {
20211            if (unknownOption.parent()) unknownOption.remove();
20212            ngModelCtrl.$setViewValue(selectElement.val());
20213          });
20214        });
20215      }
20216
20217      function setupAsMultiple(scope, selectElement, ctrl) {
20218        var lastView;
20219        ctrl.$render = function() {
20220          var items = new HashMap(ctrl.$viewValue);
20221          forEach(selectElement.find('option'), function(option) {
20222            option.selected = isDefined(items.get(option.value));
20223          });
20224        };
20225
20226        // we have to do it on each watch since ngModel watches reference, but
20227        // we need to work of an array, so we need to see if anything was inserted/removed
20228        scope.$watch(function selectMultipleWatch() {
20229          if (!equals(lastView, ctrl.$viewValue)) {
20230            lastView = copy(ctrl.$viewValue);
20231            ctrl.$render();
20232          }
20233        });
20234
20235        selectElement.on('change', function() {
20236          scope.$apply(function() {
20237            var array = [];
20238            forEach(selectElement.find('option'), function(option) {
20239              if (option.selected) {
20240                array.push(option.value);
20241              }
20242            });
20243            ctrl.$setViewValue(array);
20244          });
20245        });
20246      }
20247
20248      function setupAsOptions(scope, selectElement, ctrl) {
20249        var match;
20250
20251        if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
20252          throw ngOptionsMinErr('iexp',
20253            "Expected expression in form of " +
20254            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
20255            " but got '{0}'. Element: {1}",
20256            optionsExp, startingTag(selectElement));
20257        }
20258
20259        var displayFn = $parse(match[2] || match[1]),
20260            valueName = match[4] || match[6],
20261            keyName = match[5],
20262            groupByFn = $parse(match[3] || ''),
20263            valueFn = $parse(match[2] ? match[1] : valueName),
20264            valuesFn = $parse(match[7]),
20265            track = match[8],
20266            trackFn = track ? $parse(match[8]) : null,
20267            // This is an array of array of existing option groups in DOM.
20268            // We try to reuse these if possible
20269            // - optionGroupsCache[0] is the options with no option group
20270            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
20271            optionGroupsCache = [[{element: selectElement, label:''}]];
20272
20273        if (nullOption) {
20274          // compile the element since there might be bindings in it
20275          $compile(nullOption)(scope);
20276
20277          // remove the class, which is added automatically because we recompile the element and it
20278          // becomes the compilation root
20279          nullOption.removeClass('ng-scope');
20280
20281          // we need to remove it before calling selectElement.empty() because otherwise IE will
20282          // remove the label from the element. wtf?
20283          nullOption.remove();
20284        }
20285
20286        // clear contents, we'll add what's needed based on the model
20287        selectElement.empty();
20288
20289        selectElement.on('change', function() {
20290          scope.$apply(function() {
20291            var optionGroup,
20292                collection = valuesFn(scope) || [],
20293                locals = {},
20294                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
20295
20296            if (multiple) {
20297              value = [];
20298              for (groupIndex = 0, groupLength = optionGroupsCache.length;
20299                   groupIndex < groupLength;
20300                   groupIndex++) {
20301                // list of options for that group. (first item has the parent)
20302                optionGroup = optionGroupsCache[groupIndex];
20303
20304                for(index = 1, length = optionGroup.length; index < length; index++) {
20305                  if ((optionElement = optionGroup[index].element)[0].selected) {
20306                    key = optionElement.val();
20307                    if (keyName) locals[keyName] = key;
20308                    if (trackFn) {
20309                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
20310                        locals[valueName] = collection[trackIndex];
20311                        if (trackFn(scope, locals) == key) break;
20312                      }
20313                    } else {
20314                      locals[valueName] = collection[key];
20315                    }
20316                    value.push(valueFn(scope, locals));
20317                  }
20318                }
20319              }
20320            } else {
20321              key = selectElement.val();
20322              if (key == '?') {
20323                value = undefined;
20324              } else if (key === ''){
20325                value = null;
20326              } else {
20327                if (trackFn) {
20328                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
20329                    locals[valueName] = collection[trackIndex];
20330                    if (trackFn(scope, locals) == key) {
20331                      value = valueFn(scope, locals);
20332                      break;
20333                    }
20334                  }
20335                } else {
20336                  locals[valueName] = collection[key];
20337                  if (keyName) locals[keyName] = key;
20338                  value = valueFn(scope, locals);
20339                }
20340              }
20341            }
20342            ctrl.$setViewValue(value);
20343          });
20344        });
20345
20346        ctrl.$render = render;
20347
20348        // TODO(vojta): can't we optimize this ?
20349        scope.$watch(render);
20350
20351        function render() {
20352              // Temporary location for the option groups before we render them
20353          var optionGroups = {'':[]},
20354              optionGroupNames = [''],
20355              optionGroupName,
20356              optionGroup,
20357              option,
20358              existingParent, existingOptions, existingOption,
20359              modelValue = ctrl.$modelValue,
20360              values = valuesFn(scope) || [],
20361              keys = keyName ? sortedKeys(values) : values,
20362              key,
20363              groupLength, length,
20364              groupIndex, index,
20365              locals = {},
20366              selected,
20367              selectedSet = false, // nothing is selected yet
20368              lastElement,
20369              element,
20370              label;
20371
20372          if (multiple) {
20373            if (trackFn && isArray(modelValue)) {
20374              selectedSet = new HashMap([]);
20375              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
20376                locals[valueName] = modelValue[trackIndex];
20377                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
20378              }
20379            } else {
20380              selectedSet = new HashMap(modelValue);
20381            }
20382          }
20383
20384          // We now build up the list of options we need (we merge later)
20385          for (index = 0; length = keys.length, index < length; index++) {
20386
20387            key = index;
20388            if (keyName) {
20389              key = keys[index];
20390              if ( key.charAt(0) === '$' ) continue;
20391              locals[keyName] = key;
20392            }
20393
20394            locals[valueName] = values[key];
20395
20396            optionGroupName = groupByFn(scope, locals) || '';
20397            if (!(optionGroup = optionGroups[optionGroupName])) {
20398              optionGroup = optionGroups[optionGroupName] = [];
20399              optionGroupNames.push(optionGroupName);
20400            }
20401            if (multiple) {
20402              selected = isDefined(
20403                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
20404              );
20405            } else {
20406              if (trackFn) {
20407                var modelCast = {};
20408                modelCast[valueName] = modelValue;
20409                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
20410              } else {
20411                selected = modelValue === valueFn(scope, locals);
20412              }
20413              selectedSet = selectedSet || selected; // see if at least one item is selected
20414            }
20415            label = displayFn(scope, locals); // what will be seen by the user
20416
20417            // doing displayFn(scope, locals) || '' overwrites zero values
20418            label = isDefined(label) ? label : '';
20419            optionGroup.push({
20420              // either the index into array or key from object
20421              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
20422              label: label,
20423              selected: selected                   // determine if we should be selected
20424            });
20425          }
20426          if (!multiple) {
20427            if (nullOption || modelValue === null) {
20428              // insert null option if we have a placeholder, or the model is null
20429              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
20430            } else if (!selectedSet) {
20431              // option could not be found, we have to insert the undefined item
20432              optionGroups[''].unshift({id:'?', label:'', selected:true});
20433            }
20434          }
20435
20436          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
20437          for (groupIndex = 0, groupLength = optionGroupNames.length;
20438               groupIndex < groupLength;
20439               groupIndex++) {
20440            // current option group name or '' if no group
20441            optionGroupName = optionGroupNames[groupIndex];
20442
20443            // list of options for that group. (first item has the parent)
20444            optionGroup = optionGroups[optionGroupName];
20445
20446            if (optionGroupsCache.length <= groupIndex) {
20447              // we need to grow the optionGroups
20448              existingParent = {
20449                element: optGroupTemplate.clone().attr('label', optionGroupName),
20450                label: optionGroup.label
20451              };
20452              existingOptions = [existingParent];
20453              optionGroupsCache.push(existingOptions);
20454              selectElement.append(existingParent.element);
20455            } else {
20456              existingOptions = optionGroupsCache[groupIndex];
20457              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
20458
20459              // update the OPTGROUP label if not the same.
20460              if (existingParent.label != optionGroupName) {
20461                existingParent.element.attr('label', existingParent.label = optionGroupName);
20462              }
20463            }
20464
20465            lastElement = null;  // start at the beginning
20466            for(index = 0, length = optionGroup.length; index < length; index++) {
20467              option = optionGroup[index];
20468              if ((existingOption = existingOptions[index+1])) {
20469                // reuse elements
20470                lastElement = existingOption.element;
20471                if (existingOption.label !== option.label) {
20472                  lastElement.text(existingOption.label = option.label);
20473                }
20474                if (existingOption.id !== option.id) {
20475                  lastElement.val(existingOption.id = option.id);
20476                }
20477                // lastElement.prop('selected') provided by jQuery has side-effects
20478                if (lastElement[0].selected !== option.selected) {
20479                  lastElement.prop('selected', (existingOption.selected = option.selected));
20480                }
20481              } else {
20482                // grow elements
20483
20484                // if it's a null option
20485                if (option.id === '' && nullOption) {
20486                  // put back the pre-compiled element
20487                  element = nullOption;
20488                } else {
20489                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
20490                  // in this version of jQuery on some browser the .text() returns a string
20491                  // rather then the element.
20492                  (element = optionTemplate.clone())
20493                      .val(option.id)
20494                      .attr('selected', option.selected)
20495                      .text(option.label);
20496                }
20497
20498                existingOptions.push(existingOption = {
20499                    element: element,
20500                    label: option.label,
20501                    id: option.id,
20502                    selected: option.selected
20503                });
20504                if (lastElement) {
20505                  lastElement.after(element);
20506                } else {
20507                  existingParent.element.append(element);
20508                }
20509                lastElement = element;
20510              }
20511            }
20512            // remove any excessive OPTIONs in a group
20513            index++; // increment since the existingOptions[0] is parent element not OPTION
20514            while(existingOptions.length > index) {
20515              existingOptions.pop().element.remove();
20516            }
20517          }
20518          // remove any excessive OPTGROUPs from select
20519          while(optionGroupsCache.length > groupIndex) {
20520            optionGroupsCache.pop()[0].element.remove();
20521          }
20522        }
20523      }
20524    }
20525  };
20526}];
20527
20528var optionDirective = ['$interpolate', function($interpolate) {
20529  var nullSelectCtrl = {
20530    addOption: noop,
20531    removeOption: noop
20532  };
20533
20534  return {
20535    restrict: 'E',
20536    priority: 100,
20537    compile: function(element, attr) {
20538      if (isUndefined(attr.value)) {
20539        var interpolateFn = $interpolate(element.text(), true);
20540        if (!interpolateFn) {
20541          attr.$set('value', element.text());
20542        }
20543      }
20544
20545      return function (scope, element, attr) {
20546        var selectCtrlName = '$selectController',
20547            parent = element.parent(),
20548            selectCtrl = parent.data(selectCtrlName) ||
20549              parent.parent().data(selectCtrlName); // in case we are in optgroup
20550
20551        if (selectCtrl && selectCtrl.databound) {
20552          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
20553          // We don't want the view to drive the initialization of the model anyway.
20554          element.prop('selected', false);
20555        } else {
20556          selectCtrl = nullSelectCtrl;
20557        }
20558
20559        if (interpolateFn) {
20560          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
20561            attr.$set('value', newVal);
20562            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
20563            selectCtrl.addOption(newVal);
20564          });
20565        } else {
20566          selectCtrl.addOption(attr.value);
20567        }
20568
20569        element.on('$destroy', function() {
20570          selectCtrl.removeOption(attr.value);
20571        });
20572      };
20573    }
20574  };
20575}];
20576
20577var styleDirective = valueFn({
20578  restrict: 'E',
20579  terminal: true
20580});
20581
20582  //try to bind to jquery now so that one can write angular.element().read()
20583  //but we will rebind on bootstrap again.
20584  bindJQuery();
20585
20586  publishExternalAPI(angular);
20587
20588  jqLite(document).ready(function() {
20589    angularInit(document, bootstrap);
20590  });
20591
20592})(window, document);
20593
20594!angular.$$csp() && 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;}</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.